react-native-zcash 0.4.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +6 -3
  3. package/android/build.gradle +5 -4
  4. package/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/2230000.json +8 -0
  5. package/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/2240000.json +8 -0
  6. package/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/2250000.json +8 -0
  7. package/android/src/main/java/app/edge/rnzcash/RNZcashModule.kt +117 -122
  8. package/ios/RNZcash.m +1 -12
  9. package/ios/RNZcash.swift +127 -153
  10. package/ios/ZCashLightClientKit/Block/Actions/Action.swift +98 -0
  11. package/ios/ZCashLightClientKit/Block/Actions/ClearAlreadyScannedBlocksAction.swift +35 -0
  12. package/ios/ZCashLightClientKit/Block/Actions/ClearCacheAction.swift +30 -0
  13. package/ios/ZCashLightClientKit/Block/Actions/DownloadAction.swift +67 -0
  14. package/ios/ZCashLightClientKit/Block/Actions/EnhanceAction.swift +97 -0
  15. package/ios/ZCashLightClientKit/Block/Actions/FetchUTXOsAction.swift +33 -0
  16. package/ios/ZCashLightClientKit/Block/Actions/MigrateLegacyCacheDBAction.swift +70 -0
  17. package/ios/ZCashLightClientKit/Block/Actions/ProcessSuggestedScanRangesAction.swift +59 -0
  18. package/ios/ZCashLightClientKit/Block/Actions/RewindAction.swift +48 -0
  19. package/ios/ZCashLightClientKit/Block/Actions/SaplingParamsAction.swift +33 -0
  20. package/ios/ZCashLightClientKit/Block/Actions/ScanAction.swift +95 -0
  21. package/ios/ZCashLightClientKit/Block/Actions/UpdateChainTipAction.swift +55 -0
  22. package/ios/ZCashLightClientKit/Block/Actions/UpdateSubtreeRootsAction.swift +58 -0
  23. package/ios/ZCashLightClientKit/Block/Actions/ValidateServerAction.swift +60 -0
  24. package/ios/ZCashLightClientKit/Block/CompactBlockProcessor.swift +421 -937
  25. package/ios/ZCashLightClientKit/Block/Download/BlockDownloader.swift +31 -17
  26. package/ios/ZCashLightClientKit/Block/Download/BlockDownloaderService.swift +2 -2
  27. package/ios/ZCashLightClientKit/Block/Enhance/BlockEnhancer.swift +46 -15
  28. package/ios/ZCashLightClientKit/Block/FetchUnspentTxOutputs/UTXOFetcher.swift +4 -15
  29. package/ios/ZCashLightClientKit/Block/FilesystemStorage/FSCompactBlockRepository.swift +4 -4
  30. package/ios/ZCashLightClientKit/Block/Scan/BlockScanner.swift +10 -35
  31. package/ios/ZCashLightClientKit/Block/Utils/CompactBlockProgress.swift +24 -0
  32. package/ios/ZCashLightClientKit/Block/Utils/SyncControlData.swift +25 -0
  33. package/ios/ZCashLightClientKit/ClosureSynchronizer.swift +1 -2
  34. package/ios/ZCashLightClientKit/CombineSynchronizer.swift +2 -5
  35. package/ios/ZCashLightClientKit/Constants/ZcashSDK.swift +7 -25
  36. package/ios/ZCashLightClientKit/DAO/TransactionDao.swift +40 -42
  37. package/ios/ZCashLightClientKit/DAO/UnspentTransactionOutputDao.swift +13 -4
  38. package/ios/ZCashLightClientKit/Entity/AccountEntity.swift +9 -0
  39. package/ios/ZCashLightClientKit/Entity/TransactionEntity.swift +7 -10
  40. package/ios/ZCashLightClientKit/Error/Sourcery/generateErrorCode.sh +1 -1
  41. package/ios/ZCashLightClientKit/Error/ZcashError.swift +121 -12
  42. package/ios/ZCashLightClientKit/Error/ZcashErrorCode.swift +43 -5
  43. package/ios/ZCashLightClientKit/Error/ZcashErrorCodeDefinition.swift +72 -6
  44. package/ios/ZCashLightClientKit/Extensions/Bool+ToData.swift +15 -0
  45. package/ios/ZCashLightClientKit/Extensions/Data+ToOtherTypes.swift +18 -0
  46. package/ios/ZCashLightClientKit/Extensions/Int+ToData.swift +15 -0
  47. package/ios/ZCashLightClientKit/Initializer.swift +47 -26
  48. package/ios/ZCashLightClientKit/Metrics/SDKMetrics.swift +0 -12
  49. package/ios/ZCashLightClientKit/Model/Checkpoint.swift +12 -0
  50. package/ios/ZCashLightClientKit/Model/ScanProgress.swift +29 -0
  51. package/ios/ZCashLightClientKit/Model/ScanRange.swift +31 -0
  52. package/ios/ZCashLightClientKit/Modules/Service/GRPC/LightWalletGRPCService.swift +15 -0
  53. package/ios/ZCashLightClientKit/Modules/Service/GRPC/ProtoBuf/compact_formats.pb.swift +150 -46
  54. package/ios/ZCashLightClientKit/Modules/Service/GRPC/ProtoBuf/proto/compact_formats.proto +30 -16
  55. package/ios/ZCashLightClientKit/Modules/Service/GRPC/ProtoBuf/proto/service.proto +32 -6
  56. package/ios/ZCashLightClientKit/Modules/Service/GRPC/ProtoBuf/service.grpc.swift +259 -22
  57. package/ios/ZCashLightClientKit/Modules/Service/GRPC/ProtoBuf/service.pb.swift +193 -7
  58. package/ios/ZCashLightClientKit/Modules/Service/LightWalletService.swift +8 -0
  59. package/ios/ZCashLightClientKit/Providers/LatestBlocksDataProvider.swift +18 -28
  60. package/ios/ZCashLightClientKit/Repository/CompactBlockRepository.swift +1 -1
  61. package/ios/ZCashLightClientKit/Repository/TransactionRepository.swift +2 -6
  62. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2092500.json +8 -0
  63. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2095000.json +8 -0
  64. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2097500.json +8 -0
  65. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2102500.json +8 -0
  66. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2105000.json +8 -0
  67. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2107500.json +8 -0
  68. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2112500.json +8 -0
  69. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2115000.json +8 -0
  70. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2117500.json +8 -0
  71. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2122500.json +8 -0
  72. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2125000.json +8 -0
  73. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2127500.json +8 -0
  74. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2132500.json +8 -0
  75. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2135000.json +8 -0
  76. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2137500.json +8 -0
  77. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2142500.json +8 -0
  78. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2145000.json +8 -0
  79. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2147500.json +8 -0
  80. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2152500.json +8 -0
  81. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2155000.json +8 -0
  82. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2157500.json +8 -0
  83. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2162500.json +8 -0
  84. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2165000.json +8 -0
  85. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2167500.json +8 -0
  86. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2172500.json +8 -0
  87. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2175000.json +8 -0
  88. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2177500.json +8 -0
  89. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2182500.json +8 -0
  90. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2185000.json +8 -0
  91. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2187500.json +8 -0
  92. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2192500.json +8 -0
  93. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2195000.json +8 -0
  94. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2197500.json +8 -0
  95. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2202500.json +8 -0
  96. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2205000.json +8 -0
  97. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2207500.json +8 -0
  98. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2212500.json +8 -0
  99. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2215000.json +8 -0
  100. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2217500.json +8 -0
  101. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2222500.json +8 -0
  102. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2225000.json +8 -0
  103. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2227500.json +8 -0
  104. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2230000.json +8 -0
  105. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2232500.json +8 -0
  106. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2235000.json +8 -0
  107. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2237500.json +8 -0
  108. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2240000.json +8 -0
  109. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2242500.json +8 -0
  110. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2245000.json +8 -0
  111. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2247500.json +8 -0
  112. package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2250000.json +8 -0
  113. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2350000.json +8 -0
  114. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2360000.json +8 -0
  115. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2370000.json +8 -0
  116. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2380000.json +8 -0
  117. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2390000.json +8 -0
  118. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2400000.json +8 -0
  119. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2410000.json +8 -0
  120. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2420000.json +8 -0
  121. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2430000.json +8 -0
  122. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2440000.json +8 -0
  123. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2450000.json +8 -0
  124. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2460000.json +8 -0
  125. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2470000.json +8 -0
  126. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2480000.json +8 -0
  127. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2490000.json +8 -0
  128. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2500000.json +8 -0
  129. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2510000.json +8 -0
  130. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2520000.json +8 -0
  131. package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2530000.json +8 -0
  132. package/ios/ZCashLightClientKit/Rust/ZcashRustBackend.swift +293 -158
  133. package/ios/ZCashLightClientKit/Rust/ZcashRustBackendWelding.swift +58 -64
  134. package/ios/ZCashLightClientKit/Rust/zcashlc.h +618 -512
  135. package/ios/ZCashLightClientKit/Synchronizer/ClosureSDKSynchronizer.swift +2 -8
  136. package/ios/ZCashLightClientKit/Synchronizer/CombineSDKSynchronizer.swift +3 -15
  137. package/ios/ZCashLightClientKit/Synchronizer/Dependencies.swift +11 -30
  138. package/ios/ZCashLightClientKit/Synchronizer/SDKSynchronizer.swift +41 -50
  139. package/ios/ZCashLightClientKit/Synchronizer.swift +51 -65
  140. package/ios/ZCashLightClientKit/Transaction/TransactionEncoder.swift +2 -2
  141. package/ios/ZCashLightClientKit/Transaction/WalletTransactionEncoder.swift +7 -7
  142. package/ios/ZCashLightClientKit/Utils/OSLogger.swift +3 -3
  143. package/ios/ZCashLightClientKit/Utils/ZcashFileManager.swift +16 -0
  144. package/ios/libzcashlc.xcframework/Info.plist +9 -5
  145. package/ios/libzcashlc.xcframework/ios-arm64/libzcashlc.a +0 -0
  146. package/ios/libzcashlc.xcframework/ios-arm64_x86_64-simulator/libzcashlc.a +0 -0
  147. package/lib/rnzcash.rn.js +8 -30
  148. package/lib/rnzcash.rn.js.map +1 -1
  149. package/lib/src/react-native.d.ts +3 -5
  150. package/lib/src/types.d.ts +19 -14
  151. package/package.json +1 -1
  152. package/src/react-native.ts +13 -21
  153. package/src/types.ts +26 -23
  154. package/ios/ZCashLightClientKit/Block/Utils/InternalSyncProgress.swift +0 -200
  155. package/ios/ZCashLightClientKit/Block/Validate/BlockValidator.swift +0 -51
  156. package/ios/ZCashLightClientKit/DAO/BlockDao.swift +0 -112
  157. package/ios/ZCashLightClientKit/Entity/BlockProgress.swift +0 -24
@@ -0,0 +1,97 @@
1
+ //
2
+ // EnhanceAction.swift
3
+ //
4
+ //
5
+ // Created by Michal Fousek on 05.05.2023.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ final class EnhanceAction {
11
+ let blockEnhancer: BlockEnhancer
12
+ let configProvider: CompactBlockProcessor.ConfigProvider
13
+ let logger: Logger
14
+
15
+ init(container: DIContainer, configProvider: CompactBlockProcessor.ConfigProvider) {
16
+ blockEnhancer = container.resolve(BlockEnhancer.self)
17
+ self.configProvider = configProvider
18
+ logger = container.resolve(Logger.self)
19
+ }
20
+
21
+ func decideWhatToDoNext(context: ActionContext, lastScannedHeight: BlockHeight) async -> ActionContext {
22
+ guard await context.syncControlData.latestScannedHeight != nil else {
23
+ await context.update(state: .clearCache)
24
+ return context
25
+ }
26
+
27
+ let latestBlockHeight = await context.syncControlData.latestBlockHeight
28
+ if lastScannedHeight >= latestBlockHeight {
29
+ await context.update(state: .clearCache)
30
+ } else {
31
+ await context.update(state: .updateChainTip)
32
+ }
33
+
34
+ return context
35
+ }
36
+ }
37
+
38
+ extension EnhanceAction: Action {
39
+ var removeBlocksCacheWhenFailed: Bool { false }
40
+
41
+ func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
42
+ // Use `BlockEnhancer` to enhance blocks.
43
+ // This action is executed on each downloaded and scanned batch (typically each 100 blocks). But we want to run enhancement each 1000 blocks.
44
+
45
+ // if latestScannedHeight >= context.scanRanges.scanRange.upperBound then everything is processed and sync process should continue to end.
46
+ // If latestScannedHeight < context.scanRanges.scanRange.upperBound then set state to `download` because there are blocks to
47
+ // download and scan.
48
+
49
+ let config = await configProvider.config
50
+ guard let lastScannedHeight = await context.lastScannedHeight else {
51
+ throw ZcashError.compactBlockProcessorLastScannedHeight
52
+ }
53
+
54
+ guard let firstUnenhancedHeight = await context.syncControlData.firstUnenhancedHeight else {
55
+ return await decideWhatToDoNext(context: context, lastScannedHeight: lastScannedHeight)
56
+ }
57
+
58
+ let latestBlockHeight = await context.syncControlData.latestBlockHeight
59
+ let lastEnhancedHeight: BlockHeight
60
+ if let lastEnhancedHeightInContext = await context.lastEnhancedHeight {
61
+ lastEnhancedHeight = lastEnhancedHeightInContext
62
+ } else {
63
+ lastEnhancedHeight = -1
64
+ }
65
+ let enhanceRangeStart = max(firstUnenhancedHeight, lastEnhancedHeight + 1)
66
+ let enhanceRangeEnd = min(latestBlockHeight, lastScannedHeight)
67
+
68
+ // This may happen:
69
+ // For example whole enhance range is 0...2100 Without this force enhance is done for ranges: 0...1000, 1001...2000. And that's it.
70
+ // Last 100 blocks isn't enhanced.
71
+ //
72
+ // This force makes sure that all the blocks are enhanced even when last enhance happened < 1000 blocks ago.
73
+ let forceEnhance = enhanceRangeEnd == latestBlockHeight && enhanceRangeEnd - enhanceRangeStart <= config.enhanceBatchSize
74
+
75
+ if enhanceRangeStart <= enhanceRangeEnd && (forceEnhance || (lastScannedHeight - lastEnhancedHeight >= config.enhanceBatchSize)) {
76
+ let enhanceRange = enhanceRangeStart...enhanceRangeEnd
77
+ let transactions = try await blockEnhancer.enhance(
78
+ at: enhanceRange,
79
+ didEnhance: { progress in
80
+ if let foundTx = progress.lastFoundTransaction, progress.newlyMined {
81
+ await didUpdate(.minedTransaction(foundTx))
82
+ }
83
+ }
84
+ )
85
+
86
+ await context.update(lastEnhancedHeight: enhanceRange.upperBound)
87
+
88
+ if let transactions {
89
+ await didUpdate(.foundTransactions(transactions, enhanceRange))
90
+ }
91
+ }
92
+
93
+ return await decideWhatToDoNext(context: context, lastScannedHeight: lastScannedHeight)
94
+ }
95
+
96
+ func stop() async { }
97
+ }
@@ -0,0 +1,33 @@
1
+ //
2
+ // FetchUTXOsAction.swift
3
+ //
4
+ //
5
+ // Created by Michal Fousek on 05.05.2023.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ final class FetchUTXOsAction {
11
+ let utxoFetcher: UTXOFetcher
12
+ let logger: Logger
13
+
14
+ init(container: DIContainer) {
15
+ utxoFetcher = container.resolve(UTXOFetcher.self)
16
+ logger = container.resolve(Logger.self)
17
+ }
18
+ }
19
+
20
+ extension FetchUTXOsAction: Action {
21
+ var removeBlocksCacheWhenFailed: Bool { false }
22
+
23
+ func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
24
+ logger.debug("Fetching UTXOs")
25
+ let result = try await utxoFetcher.fetch() { _ in }
26
+ await didUpdate(.storedUTXOs(result))
27
+
28
+ await context.update(state: .handleSaplingParams)
29
+ return context
30
+ }
31
+
32
+ func stop() async { }
33
+ }
@@ -0,0 +1,70 @@
1
+ //
2
+ // MigrateLegacyCacheDB.swift
3
+ //
4
+ //
5
+ // Created by Michal Fousek on 10.05.2023.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ final class MigrateLegacyCacheDBAction {
11
+ private let configProvider: CompactBlockProcessor.ConfigProvider
12
+ private let storage: CompactBlockRepository
13
+ private let transactionRepository: TransactionRepository
14
+ private let fileManager: ZcashFileManager
15
+
16
+ init(container: DIContainer, configProvider: CompactBlockProcessor.ConfigProvider) {
17
+ self.configProvider = configProvider
18
+ storage = container.resolve(CompactBlockRepository.self)
19
+ transactionRepository = container.resolve(TransactionRepository.self)
20
+ fileManager = container.resolve(ZcashFileManager.self)
21
+ }
22
+
23
+ private func updateState(_ context: ActionContext) async -> ActionContext {
24
+ await context.update(state: .validateServer)
25
+ return context
26
+ }
27
+ }
28
+
29
+ extension MigrateLegacyCacheDBAction: Action {
30
+ var removeBlocksCacheWhenFailed: Bool { false }
31
+
32
+ func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
33
+ let config = await configProvider.config
34
+ guard let legacyCacheDbURL = config.cacheDbURL else {
35
+ return await updateState(context)
36
+ }
37
+
38
+ guard legacyCacheDbURL != config.fsBlockCacheRoot else {
39
+ throw ZcashError.compactBlockProcessorCacheDbMigrationFsCacheMigrationFailedSameURL
40
+ }
41
+
42
+ // Instance with alias `default` is same as instance before the Alias was introduced. So it makes sense that only this instance handles
43
+ // legacy cache DB. Any instance with different than `default` alias was created after the Alias was introduced and at this point legacy
44
+ // cache DB doesn't exist anymore. So there is nothing to migrate for instances with not default Alias.
45
+ guard config.alias == .default else {
46
+ return await updateState(context)
47
+ }
48
+
49
+ // if the URL provided is not readable, it means that the client has a reference
50
+ // to the cacheDb file but it has been deleted in a prior sync cycle. there's
51
+ // nothing to do here.
52
+ guard fileManager.isReadableFile(atPath: legacyCacheDbURL.path) else {
53
+ return await updateState(context)
54
+ }
55
+
56
+ do {
57
+ // if there's a readable file at the provided URL, delete it.
58
+ try fileManager.removeItem(at: legacyCacheDbURL)
59
+ } catch {
60
+ throw ZcashError.compactBlockProcessorCacheDbMigrationFailedToDeleteLegacyDb(error)
61
+ }
62
+
63
+ // create the storage
64
+ try await self.storage.create()
65
+
66
+ return await updateState(context)
67
+ }
68
+
69
+ func stop() { }
70
+ }
@@ -0,0 +1,59 @@
1
+ //
2
+ // ProcessSuggestedScanRangesAction.swift
3
+ //
4
+ //
5
+ // Created by Lukáš Korba on 02.08.2023.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ final class ProcessSuggestedScanRangesAction {
11
+ let rustBackend: ZcashRustBackendWelding
12
+ let service: LightWalletService
13
+ let logger: Logger
14
+
15
+ init(container: DIContainer) {
16
+ service = container.resolve(LightWalletService.self)
17
+ rustBackend = container.resolve(ZcashRustBackendWelding.self)
18
+ logger = container.resolve(Logger.self)
19
+ }
20
+ }
21
+
22
+ extension ProcessSuggestedScanRangesAction: Action {
23
+ var removeBlocksCacheWhenFailed: Bool { false }
24
+
25
+ func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
26
+ logger.info("Getting the suggested scan ranges from the wallet database.")
27
+ let scanRanges = try await rustBackend.suggestScanRanges()
28
+
29
+ if let firstRange = scanRanges.first {
30
+ let rangeStartExclusive = firstRange.range.lowerBound - 1
31
+ let rangeEndInclusive = firstRange.range.upperBound - 1
32
+
33
+ let syncControlData = SyncControlData(
34
+ latestBlockHeight: rangeEndInclusive,
35
+ latestScannedHeight: rangeStartExclusive,
36
+ firstUnenhancedHeight: rangeStartExclusive + 1
37
+ )
38
+
39
+ logger.debug("""
40
+ Init numbers:
41
+ latestBlockHeight [BC]: \(rangeEndInclusive)
42
+ latestScannedHeight [DB]: \(rangeStartExclusive)
43
+ firstUnenhancedHeight [DB]: \(rangeStartExclusive + 1)
44
+ """)
45
+
46
+ await context.update(lastScannedHeight: rangeStartExclusive)
47
+ await context.update(lastDownloadedHeight: rangeStartExclusive)
48
+ await context.update(syncControlData: syncControlData)
49
+
50
+ await context.update(state: .download)
51
+ } else {
52
+ await context.update(state: .finished)
53
+ }
54
+
55
+ return context
56
+ }
57
+
58
+ func stop() async { }
59
+ }
@@ -0,0 +1,48 @@
1
+ //
2
+ // RewindAction.swift
3
+ //
4
+ //
5
+ // Created by Lukáš Korba on 09.08.2023.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ final class RewindAction {
11
+ let downloader: BlockDownloader
12
+ let rustBackend: ZcashRustBackendWelding
13
+ let downloaderService: BlockDownloaderService
14
+ let logger: Logger
15
+
16
+ init(container: DIContainer) {
17
+ downloader = container.resolve(BlockDownloader.self)
18
+ rustBackend = container.resolve(ZcashRustBackendWelding.self)
19
+ downloaderService = container.resolve(BlockDownloaderService.self)
20
+ logger = container.resolve(Logger.self)
21
+ }
22
+
23
+ private func update(context: ActionContext) async -> ActionContext {
24
+ await context.update(state: .processSuggestedScanRanges)
25
+ return context
26
+ }
27
+ }
28
+
29
+ extension RewindAction: Action {
30
+ var removeBlocksCacheWhenFailed: Bool { false }
31
+
32
+ func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
33
+ guard let rewindHeight = await context.requestedRewindHeight else {
34
+ return await update(context: context)
35
+ }
36
+
37
+ logger.debug("Executing rewind.")
38
+ await downloader.rewind(latestDownloadedBlockHeight: rewindHeight)
39
+ try await rustBackend.rewindToHeight(height: Int32(rewindHeight))
40
+
41
+ // clear cache
42
+ try await downloaderService.rewind(to: rewindHeight)
43
+
44
+ return await update(context: context)
45
+ }
46
+
47
+ func stop() async { }
48
+ }
@@ -0,0 +1,33 @@
1
+ //
2
+ // SaplingParamsAction.swift
3
+ //
4
+ //
5
+ // Created by Michal Fousek on 05.05.2023.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ final class SaplingParamsAction {
11
+ let saplingParametersHandler: SaplingParametersHandler
12
+ let logger: Logger
13
+
14
+ init(container: DIContainer) {
15
+ saplingParametersHandler = container.resolve(SaplingParametersHandler.self)
16
+ logger = container.resolve(Logger.self)
17
+ }
18
+ }
19
+
20
+ extension SaplingParamsAction: Action {
21
+ var removeBlocksCacheWhenFailed: Bool { false }
22
+
23
+ func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
24
+ logger.debug("Fetching sapling parameters")
25
+ try await saplingParametersHandler.handleIfNeeded()
26
+
27
+ await context.update(state: .updateSubtreeRoots)
28
+
29
+ return context
30
+ }
31
+
32
+ func stop() async { }
33
+ }
@@ -0,0 +1,95 @@
1
+ //
2
+ // ScanAction.swift
3
+ //
4
+ //
5
+ // Created by Michal Fousek on 05.05.2023.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ final class ScanAction {
11
+ let configProvider: CompactBlockProcessor.ConfigProvider
12
+ let blockScanner: BlockScanner
13
+ let rustBackend: ZcashRustBackendWelding
14
+ let latestBlocksDataProvider: LatestBlocksDataProvider
15
+ let logger: Logger
16
+
17
+ init(container: DIContainer, configProvider: CompactBlockProcessor.ConfigProvider) {
18
+ self.configProvider = configProvider
19
+ blockScanner = container.resolve(BlockScanner.self)
20
+ rustBackend = container.resolve(ZcashRustBackendWelding.self)
21
+ latestBlocksDataProvider = container.resolve(LatestBlocksDataProvider.self)
22
+ logger = container.resolve(Logger.self)
23
+ }
24
+
25
+ private func update(context: ActionContext) async -> ActionContext {
26
+ await context.update(state: .clearAlreadyScannedBlocks)
27
+ return context
28
+ }
29
+ }
30
+
31
+ extension ScanAction: Action {
32
+ var removeBlocksCacheWhenFailed: Bool { true }
33
+
34
+ func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
35
+ guard let lastScannedHeight = await context.lastScannedHeight else {
36
+ return await update(context: context)
37
+ }
38
+
39
+ let config = await configProvider.config
40
+ let latestBlockHeight = await context.syncControlData.latestBlockHeight
41
+ // This action is executed for each batch (batch size is 100 blocks by default) until all the blocks in whole `scanRange` are scanned.
42
+ // So the right range for this batch must be computed.
43
+ let batchRangeStart = lastScannedHeight
44
+ let batchRangeEnd = min(latestBlockHeight, batchRangeStart + config.batchSize)
45
+
46
+ guard batchRangeStart <= batchRangeEnd else {
47
+ return await update(context: context)
48
+ }
49
+
50
+ let batchRange = batchRangeStart...batchRangeEnd
51
+
52
+ logger.debug("Starting scan blocks with range: \(batchRange.lowerBound)...\(batchRange.upperBound)")
53
+
54
+ do {
55
+ try await blockScanner.scanBlocks(at: batchRange) { [weak self] lastScannedHeight, increment in
56
+ let processedHeight = await context.processedHeight
57
+ let incrementedprocessedHeight = processedHeight + BlockHeight(increment)
58
+ await context.update(processedHeight: incrementedprocessedHeight)
59
+ await self?.latestBlocksDataProvider.updateScannedData()
60
+
61
+ // report scan progress only if it's available
62
+ if let scanProgress = try? await self?.rustBackend.getScanProgress() {
63
+ let progress = try scanProgress.progress()
64
+ self?.logger.debug("progress: \(progress)")
65
+ await didUpdate(.syncProgress(progress))
66
+ }
67
+
68
+ // ScanAction is controlled locally so it must report back the updated scanned height
69
+ await context.update(lastScannedHeight: lastScannedHeight)
70
+ }
71
+ } catch ZcashError.rustScanBlocks(let errorMsg) {
72
+ if isContinuityError(errorMsg) {
73
+ await context.update(requestedRewindHeight: batchRange.lowerBound - 10)
74
+ await context.update(state: .rewind)
75
+ return context
76
+ } else {
77
+ throw ZcashError.rustScanBlocks(errorMsg)
78
+ }
79
+ } catch {
80
+ throw error
81
+ }
82
+
83
+ return await update(context: context)
84
+ }
85
+
86
+ func stop() async { }
87
+ }
88
+
89
+ private extension ScanAction {
90
+ func isContinuityError(_ errorMsg: String) -> Bool {
91
+ errorMsg.contains("The parent hash of proposed block does not correspond to the block hash at height")
92
+ || errorMsg.contains("Block height discontinuity at height")
93
+ || errorMsg.contains("note commitment tree size provided by a compact block did not match the expected size at height")
94
+ }
95
+ }
@@ -0,0 +1,55 @@
1
+ //
2
+ // UpdateChainTipAction.swift
3
+ //
4
+ //
5
+ // Created by Lukáš Korba on 01.08.2023.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ final class UpdateChainTipAction {
11
+ let rustBackend: ZcashRustBackendWelding
12
+ let downloader: BlockDownloader
13
+ let service: LightWalletService
14
+ let latestBlocksDataProvider: LatestBlocksDataProvider
15
+ let logger: Logger
16
+
17
+ init(container: DIContainer) {
18
+ service = container.resolve(LightWalletService.self)
19
+ downloader = container.resolve(BlockDownloader.self)
20
+ rustBackend = container.resolve(ZcashRustBackendWelding.self)
21
+ latestBlocksDataProvider = container.resolve(LatestBlocksDataProvider.self)
22
+ logger = container.resolve(Logger.self)
23
+ }
24
+
25
+ func updateChainTip(_ context: ActionContext, time: TimeInterval) async throws {
26
+ let latestBlockHeight = try await service.latestBlockHeight()
27
+
28
+ logger.info("Latest block height is \(latestBlockHeight)")
29
+ try await rustBackend.updateChainTip(height: Int32(latestBlockHeight))
30
+ await context.update(lastChainTipUpdateTime: time)
31
+ await latestBlocksDataProvider.update(latestBlockHeight)
32
+ }
33
+ }
34
+
35
+ extension UpdateChainTipAction: Action {
36
+ var removeBlocksCacheWhenFailed: Bool { false }
37
+
38
+ func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
39
+ let lastChainTipUpdateTime = await context.lastChainTipUpdateTime
40
+ let now = Date().timeIntervalSince1970
41
+
42
+ // Update chain tip can be called from different contexts
43
+ if await context.prevState == .updateSubtreeRoots || now - lastChainTipUpdateTime > 600 {
44
+ await downloader.stopDownload()
45
+ try await updateChainTip(context, time: now)
46
+ await context.update(state: .clearCache)
47
+ } else if await context.prevState == .enhance {
48
+ await context.update(state: .download)
49
+ }
50
+
51
+ return context
52
+ }
53
+
54
+ func stop() async { }
55
+ }
@@ -0,0 +1,58 @@
1
+ //
2
+ // UpdateSubtreeRootsAction.swift
3
+ //
4
+ //
5
+ // Created by Lukas Korba on 01.08.2023.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ final class UpdateSubtreeRootsAction {
11
+ let configProvider: CompactBlockProcessor.ConfigProvider
12
+ let rustBackend: ZcashRustBackendWelding
13
+ let service: LightWalletService
14
+ let logger: Logger
15
+
16
+ init(container: DIContainer, configProvider: CompactBlockProcessor.ConfigProvider) {
17
+ self.configProvider = configProvider
18
+ service = container.resolve(LightWalletService.self)
19
+ rustBackend = container.resolve(ZcashRustBackendWelding.self)
20
+ logger = container.resolve(Logger.self)
21
+ }
22
+ }
23
+
24
+ extension UpdateSubtreeRootsAction: Action {
25
+ var removeBlocksCacheWhenFailed: Bool { false }
26
+
27
+ func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
28
+ var request = GetSubtreeRootsArg()
29
+ request.shieldedProtocol = .sapling
30
+
31
+ logger.info("Attempt to get subtree roots, this may fail because lightwalletd may not support Spend before Sync.")
32
+ let stream = service.getSubtreeRoots(request)
33
+
34
+ var roots: [SubtreeRoot] = []
35
+
36
+ do {
37
+ for try await subtreeRoot in stream {
38
+ roots.append(subtreeRoot)
39
+ }
40
+ } catch ZcashError.serviceSubtreeRootsStreamFailed(LightWalletServiceError.timeOut) {
41
+ throw ZcashError.serviceSubtreeRootsStreamFailed(LightWalletServiceError.timeOut)
42
+ }
43
+
44
+ logger.info("Sapling tree has \(roots.count) subtrees")
45
+ do {
46
+ try await rustBackend.putSaplingSubtreeRoots(startIndex: UInt64(request.startIndex), roots: roots)
47
+
48
+ await context.update(state: .updateChainTip)
49
+ } catch {
50
+ logger.debug("putSaplingSubtreeRoots failed with error \(error.localizedDescription)")
51
+ throw ZcashError.compactBlockProcessorPutSaplingSubtreeRoots(error)
52
+ }
53
+
54
+ return context
55
+ }
56
+
57
+ func stop() async { }
58
+ }
@@ -0,0 +1,60 @@
1
+ //
2
+ // ValidateServerAction.swift
3
+ //
4
+ //
5
+ // Created by Michal Fousek on 05.05.2023.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ final class ValidateServerAction {
11
+ let configProvider: CompactBlockProcessor.ConfigProvider
12
+ let rustBackend: ZcashRustBackendWelding
13
+ let service: LightWalletService
14
+
15
+ init(container: DIContainer, configProvider: CompactBlockProcessor.ConfigProvider) {
16
+ self.configProvider = configProvider
17
+ rustBackend = container.resolve(ZcashRustBackendWelding.self)
18
+ service = container.resolve(LightWalletService.self)
19
+ }
20
+ }
21
+
22
+ extension ValidateServerAction: Action {
23
+ var removeBlocksCacheWhenFailed: Bool { false }
24
+
25
+ func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
26
+ let config = await configProvider.config
27
+ let info = try await service.getInfo()
28
+ let localNetwork = config.network
29
+ let saplingActivation = config.saplingActivation
30
+
31
+ // check network types
32
+ guard let remoteNetworkType = NetworkType.forChainName(info.chainName) else {
33
+ throw ZcashError.compactBlockProcessorChainName(info.chainName)
34
+ }
35
+
36
+ guard remoteNetworkType == localNetwork.networkType else {
37
+ throw ZcashError.compactBlockProcessorNetworkMismatch(localNetwork.networkType, remoteNetworkType)
38
+ }
39
+
40
+ guard saplingActivation == info.saplingActivationHeight else {
41
+ throw ZcashError.compactBlockProcessorSaplingActivationMismatch(saplingActivation, BlockHeight(info.saplingActivationHeight))
42
+ }
43
+
44
+ // check branch id
45
+ let localBranch = try rustBackend.consensusBranchIdFor(height: Int32(info.blockHeight))
46
+
47
+ guard let remoteBranchID = ConsensusBranchID.fromString(info.consensusBranchID) else {
48
+ throw ZcashError.compactBlockProcessorConsensusBranchID
49
+ }
50
+
51
+ guard remoteBranchID == localBranch else {
52
+ throw ZcashError.compactBlockProcessorWrongConsensusBranchId(localBranch, remoteBranchID)
53
+ }
54
+
55
+ await context.update(state: .fetchUTXO)
56
+ return context
57
+ }
58
+
59
+ func stop() async { }
60
+ }