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.
- package/CHANGELOG.md +24 -0
- package/README.md +6 -3
- package/android/build.gradle +5 -4
- package/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/2230000.json +8 -0
- package/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/2240000.json +8 -0
- package/android/src/main/assets/co.electriccoin.zcash/checkpoint/mainnet/2250000.json +8 -0
- package/android/src/main/java/app/edge/rnzcash/RNZcashModule.kt +117 -122
- package/ios/RNZcash.m +1 -12
- package/ios/RNZcash.swift +127 -153
- package/ios/ZCashLightClientKit/Block/Actions/Action.swift +98 -0
- package/ios/ZCashLightClientKit/Block/Actions/ClearAlreadyScannedBlocksAction.swift +35 -0
- package/ios/ZCashLightClientKit/Block/Actions/ClearCacheAction.swift +30 -0
- package/ios/ZCashLightClientKit/Block/Actions/DownloadAction.swift +67 -0
- package/ios/ZCashLightClientKit/Block/Actions/EnhanceAction.swift +97 -0
- package/ios/ZCashLightClientKit/Block/Actions/FetchUTXOsAction.swift +33 -0
- package/ios/ZCashLightClientKit/Block/Actions/MigrateLegacyCacheDBAction.swift +70 -0
- package/ios/ZCashLightClientKit/Block/Actions/ProcessSuggestedScanRangesAction.swift +59 -0
- package/ios/ZCashLightClientKit/Block/Actions/RewindAction.swift +48 -0
- package/ios/ZCashLightClientKit/Block/Actions/SaplingParamsAction.swift +33 -0
- package/ios/ZCashLightClientKit/Block/Actions/ScanAction.swift +95 -0
- package/ios/ZCashLightClientKit/Block/Actions/UpdateChainTipAction.swift +55 -0
- package/ios/ZCashLightClientKit/Block/Actions/UpdateSubtreeRootsAction.swift +58 -0
- package/ios/ZCashLightClientKit/Block/Actions/ValidateServerAction.swift +60 -0
- package/ios/ZCashLightClientKit/Block/CompactBlockProcessor.swift +421 -937
- package/ios/ZCashLightClientKit/Block/Download/BlockDownloader.swift +31 -17
- package/ios/ZCashLightClientKit/Block/Download/BlockDownloaderService.swift +2 -2
- package/ios/ZCashLightClientKit/Block/Enhance/BlockEnhancer.swift +46 -15
- package/ios/ZCashLightClientKit/Block/FetchUnspentTxOutputs/UTXOFetcher.swift +4 -15
- package/ios/ZCashLightClientKit/Block/FilesystemStorage/FSCompactBlockRepository.swift +4 -4
- package/ios/ZCashLightClientKit/Block/Scan/BlockScanner.swift +10 -35
- package/ios/ZCashLightClientKit/Block/Utils/CompactBlockProgress.swift +24 -0
- package/ios/ZCashLightClientKit/Block/Utils/SyncControlData.swift +25 -0
- package/ios/ZCashLightClientKit/ClosureSynchronizer.swift +1 -2
- package/ios/ZCashLightClientKit/CombineSynchronizer.swift +2 -5
- package/ios/ZCashLightClientKit/Constants/ZcashSDK.swift +7 -25
- package/ios/ZCashLightClientKit/DAO/TransactionDao.swift +40 -42
- package/ios/ZCashLightClientKit/DAO/UnspentTransactionOutputDao.swift +13 -4
- package/ios/ZCashLightClientKit/Entity/AccountEntity.swift +9 -0
- package/ios/ZCashLightClientKit/Entity/TransactionEntity.swift +7 -10
- package/ios/ZCashLightClientKit/Error/Sourcery/generateErrorCode.sh +1 -1
- package/ios/ZCashLightClientKit/Error/ZcashError.swift +121 -12
- package/ios/ZCashLightClientKit/Error/ZcashErrorCode.swift +43 -5
- package/ios/ZCashLightClientKit/Error/ZcashErrorCodeDefinition.swift +72 -6
- package/ios/ZCashLightClientKit/Extensions/Bool+ToData.swift +15 -0
- package/ios/ZCashLightClientKit/Extensions/Data+ToOtherTypes.swift +18 -0
- package/ios/ZCashLightClientKit/Extensions/Int+ToData.swift +15 -0
- package/ios/ZCashLightClientKit/Initializer.swift +47 -26
- package/ios/ZCashLightClientKit/Metrics/SDKMetrics.swift +0 -12
- package/ios/ZCashLightClientKit/Model/Checkpoint.swift +12 -0
- package/ios/ZCashLightClientKit/Model/ScanProgress.swift +29 -0
- package/ios/ZCashLightClientKit/Model/ScanRange.swift +31 -0
- package/ios/ZCashLightClientKit/Modules/Service/GRPC/LightWalletGRPCService.swift +15 -0
- package/ios/ZCashLightClientKit/Modules/Service/GRPC/ProtoBuf/compact_formats.pb.swift +150 -46
- package/ios/ZCashLightClientKit/Modules/Service/GRPC/ProtoBuf/proto/compact_formats.proto +30 -16
- package/ios/ZCashLightClientKit/Modules/Service/GRPC/ProtoBuf/proto/service.proto +32 -6
- package/ios/ZCashLightClientKit/Modules/Service/GRPC/ProtoBuf/service.grpc.swift +259 -22
- package/ios/ZCashLightClientKit/Modules/Service/GRPC/ProtoBuf/service.pb.swift +193 -7
- package/ios/ZCashLightClientKit/Modules/Service/LightWalletService.swift +8 -0
- package/ios/ZCashLightClientKit/Providers/LatestBlocksDataProvider.swift +18 -28
- package/ios/ZCashLightClientKit/Repository/CompactBlockRepository.swift +1 -1
- package/ios/ZCashLightClientKit/Repository/TransactionRepository.swift +2 -6
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2092500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2095000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2097500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2102500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2105000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2107500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2112500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2115000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2117500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2122500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2125000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2127500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2132500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2135000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2137500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2142500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2145000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2147500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2152500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2155000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2157500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2162500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2165000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2167500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2172500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2175000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2177500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2182500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2185000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2187500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2192500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2195000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2197500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2202500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2205000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2207500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2212500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2215000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2217500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2222500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2225000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2227500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2230000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2232500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2235000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2237500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2240000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2242500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2245000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2247500.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/mainnet/2250000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2350000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2360000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2370000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2380000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2390000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2400000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2410000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2420000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2430000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2440000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2450000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2460000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2470000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2480000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2490000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2500000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2510000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2520000.json +8 -0
- package/ios/ZCashLightClientKit/Resources/checkpoints/testnet/2530000.json +8 -0
- package/ios/ZCashLightClientKit/Rust/ZcashRustBackend.swift +293 -158
- package/ios/ZCashLightClientKit/Rust/ZcashRustBackendWelding.swift +58 -64
- package/ios/ZCashLightClientKit/Rust/zcashlc.h +618 -512
- package/ios/ZCashLightClientKit/Synchronizer/ClosureSDKSynchronizer.swift +2 -8
- package/ios/ZCashLightClientKit/Synchronizer/CombineSDKSynchronizer.swift +3 -15
- package/ios/ZCashLightClientKit/Synchronizer/Dependencies.swift +11 -30
- package/ios/ZCashLightClientKit/Synchronizer/SDKSynchronizer.swift +41 -50
- package/ios/ZCashLightClientKit/Synchronizer.swift +51 -65
- package/ios/ZCashLightClientKit/Transaction/TransactionEncoder.swift +2 -2
- package/ios/ZCashLightClientKit/Transaction/WalletTransactionEncoder.swift +7 -7
- package/ios/ZCashLightClientKit/Utils/OSLogger.swift +3 -3
- package/ios/ZCashLightClientKit/Utils/ZcashFileManager.swift +16 -0
- package/ios/libzcashlc.xcframework/Info.plist +9 -5
- package/ios/libzcashlc.xcframework/ios-arm64/libzcashlc.a +0 -0
- package/ios/libzcashlc.xcframework/ios-arm64_x86_64-simulator/libzcashlc.a +0 -0
- package/lib/rnzcash.rn.js +8 -30
- package/lib/rnzcash.rn.js.map +1 -1
- package/lib/src/react-native.d.ts +3 -5
- package/lib/src/types.d.ts +19 -14
- package/package.json +1 -1
- package/src/react-native.ts +13 -21
- package/src/types.ts +26 -23
- package/ios/ZCashLightClientKit/Block/Utils/InternalSyncProgress.swift +0 -200
- package/ios/ZCashLightClientKit/Block/Validate/BlockValidator.swift +0 -51
- package/ios/ZCashLightClientKit/DAO/BlockDao.swift +0 -112
- package/ios/ZCashLightClientKit/Entity/BlockProgress.swift +0 -24
package/ios/RNZcash.swift
CHANGED
|
@@ -8,17 +8,21 @@ var SynchronizerMap = [String: WalletSynchronizer]()
|
|
|
8
8
|
struct ConfirmedTx {
|
|
9
9
|
var minedHeight: Int
|
|
10
10
|
var toAddress: String?
|
|
11
|
+
var raw: String?
|
|
11
12
|
var rawTransactionId: String
|
|
12
13
|
var blockTimeInSeconds: Int
|
|
13
14
|
var value: String
|
|
15
|
+
var fee: String?
|
|
14
16
|
var memos: Array<String>?
|
|
15
17
|
var dictionary: [String: Any?] {
|
|
16
18
|
return [
|
|
17
19
|
"minedHeight": minedHeight,
|
|
18
20
|
"toAddress": toAddress,
|
|
21
|
+
"raw": raw,
|
|
19
22
|
"rawTransactionId": rawTransactionId,
|
|
20
23
|
"blockTimeInSeconds": blockTimeInSeconds,
|
|
21
24
|
"value": value,
|
|
25
|
+
"fee": fee,
|
|
22
26
|
"memos": memos ?? [],
|
|
23
27
|
]
|
|
24
28
|
}
|
|
@@ -42,16 +46,10 @@ struct TotalBalances {
|
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
struct ProcessorState {
|
|
45
|
-
var alias: String
|
|
46
|
-
var lastDownloadedHeight: Int
|
|
47
|
-
var lastScannedHeight: Int
|
|
48
49
|
var scanProgress: Int
|
|
49
50
|
var networkBlockHeight: Int
|
|
50
51
|
var dictionary: [String: Any] {
|
|
51
52
|
return [
|
|
52
|
-
"alias": alias,
|
|
53
|
-
"lastDownloadedHeight": lastDownloadedHeight,
|
|
54
|
-
"lastScannedHeight": lastScannedHeight,
|
|
55
53
|
"scanProgress": scanProgress,
|
|
56
54
|
"networkBlockHeight": networkBlockHeight,
|
|
57
55
|
]
|
|
@@ -83,7 +81,7 @@ class RNZcash: RCTEventEmitter {
|
|
|
83
81
|
// Synchronizer
|
|
84
82
|
@objc func initialize(
|
|
85
83
|
_ seed: String, _ birthdayHeight: Int, _ alias: String, _ networkName: String,
|
|
86
|
-
_ defaultHost: String, _ defaultPort: Int, resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
84
|
+
_ defaultHost: String, _ defaultPort: Int, _ newWallet: Bool, resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
87
85
|
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
88
86
|
) {
|
|
89
87
|
Task {
|
|
@@ -92,6 +90,7 @@ class RNZcash: RCTEventEmitter {
|
|
|
92
90
|
let initializer = Initializer(
|
|
93
91
|
cacheDbURL: try! cacheDbURLHelper(alias, network),
|
|
94
92
|
fsBlockDbRoot: try! fsBlockDbRootURLHelper(alias, network),
|
|
93
|
+
generalStorageURL: try! generalStorageURLHelper(alias, network),
|
|
95
94
|
dataDbURL: try! dataDbURLHelper(alias, network),
|
|
96
95
|
endpoint: endpoint,
|
|
97
96
|
network: network,
|
|
@@ -105,12 +104,12 @@ class RNZcash: RCTEventEmitter {
|
|
|
105
104
|
let wallet = try WalletSynchronizer(
|
|
106
105
|
alias: alias, initializer: initializer, emitter: sendToJs)
|
|
107
106
|
let seedBytes = try Mnemonic.deterministicSeedBytes(from: seed)
|
|
108
|
-
let
|
|
107
|
+
let initMode = newWallet ? WalletInitMode.newWallet : WalletInitMode.existingWallet
|
|
109
108
|
|
|
110
109
|
_ = try await wallet.synchronizer.prepare(
|
|
111
110
|
with: seedBytes,
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
walletBirthday: birthdayHeight,
|
|
112
|
+
for: initMode
|
|
114
113
|
)
|
|
115
114
|
try await wallet.synchronizer.start()
|
|
116
115
|
wallet.subscribe()
|
|
@@ -221,7 +220,7 @@ class RNZcash: RCTEventEmitter {
|
|
|
221
220
|
memo: sdkMemo
|
|
222
221
|
)
|
|
223
222
|
|
|
224
|
-
let tx: NSMutableDictionary = ["txId": broadcastTx.rawID.
|
|
223
|
+
let tx: NSMutableDictionary = ["txId": broadcastTx.rawID.toHexStringTxId()]
|
|
225
224
|
if broadcastTx.raw != nil {
|
|
226
225
|
tx["raw"] = broadcastTx.raw?.hexEncodedString()
|
|
227
226
|
}
|
|
@@ -235,97 +234,6 @@ class RNZcash: RCTEventEmitter {
|
|
|
235
234
|
}
|
|
236
235
|
}
|
|
237
236
|
|
|
238
|
-
@objc func getTransactions(
|
|
239
|
-
_ alias: String, _ first: Int, _ last: Int, resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
240
|
-
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
241
|
-
) {
|
|
242
|
-
Task {
|
|
243
|
-
if let wallet = SynchronizerMap[alias] {
|
|
244
|
-
if !wallet.fullySynced {
|
|
245
|
-
reject("GetTransactionsError", "Wallet is not synced", genericError)
|
|
246
|
-
return
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
var out: [NSDictionary] = []
|
|
250
|
-
do {
|
|
251
|
-
let txs = try await wallet.synchronizer.allTransactions()
|
|
252
|
-
let filterTxs = txs.filter {
|
|
253
|
-
$0.minedHeight != nil && $0.minedHeight! >= first && $0.minedHeight! <= last
|
|
254
|
-
&& $0.blockTime != nil
|
|
255
|
-
}
|
|
256
|
-
for tx in filterTxs {
|
|
257
|
-
var confTx = ConfirmedTx(
|
|
258
|
-
minedHeight: tx.minedHeight!,
|
|
259
|
-
rawTransactionId: (tx.rawID.toHexStringTxId()),
|
|
260
|
-
blockTimeInSeconds: Int(tx.blockTime!),
|
|
261
|
-
value: String(describing: abs(tx.value.amount))
|
|
262
|
-
)
|
|
263
|
-
if tx.isSentTransaction {
|
|
264
|
-
let recipients = await wallet.synchronizer.getRecipients(for: tx)
|
|
265
|
-
if recipients.count > 0 {
|
|
266
|
-
let addresses = recipients.compactMap {
|
|
267
|
-
if case let .address(address) = $0 {
|
|
268
|
-
return address
|
|
269
|
-
} else {
|
|
270
|
-
return nil
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
if addresses.count > 0 {
|
|
274
|
-
confTx.toAddress = addresses.first!.stringEncoded
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
if tx.memoCount > 0 {
|
|
279
|
-
let memos = (try? await wallet.synchronizer.getMemos(for: tx)) ?? []
|
|
280
|
-
let textMemos = memos.compactMap {
|
|
281
|
-
return $0.toString()
|
|
282
|
-
}
|
|
283
|
-
confTx.memos = textMemos
|
|
284
|
-
}
|
|
285
|
-
out.append(confTx.nsDictionary)
|
|
286
|
-
}
|
|
287
|
-
resolve(out)
|
|
288
|
-
} catch {
|
|
289
|
-
reject("GetTransactionsError", "Failed to get transactions", genericError)
|
|
290
|
-
}
|
|
291
|
-
} else {
|
|
292
|
-
reject("GetTransactionsError", "Wallet does not exist", genericError)
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
@objc func getBalance(
|
|
298
|
-
_ alias: String, resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
299
|
-
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
300
|
-
) {
|
|
301
|
-
Task {
|
|
302
|
-
if let wallet = SynchronizerMap[alias] {
|
|
303
|
-
do {
|
|
304
|
-
let totalShieldedBalance = try await wallet.synchronizer.getShieldedBalance()
|
|
305
|
-
let availableShieldedBalance = try await wallet.synchronizer.getShieldedVerifiedBalance()
|
|
306
|
-
|
|
307
|
-
let transparentWalletBalance = try await wallet.synchronizer.getTransparentBalance(
|
|
308
|
-
accountIndex: 0)
|
|
309
|
-
let totalTransparentBalance = transparentWalletBalance.total
|
|
310
|
-
let availableTransparentBalance = transparentWalletBalance.verified
|
|
311
|
-
|
|
312
|
-
let totalAvailable = availableShieldedBalance + availableTransparentBalance
|
|
313
|
-
let totalTotal = totalShieldedBalance + totalTransparentBalance
|
|
314
|
-
|
|
315
|
-
let balance = TotalBalances(
|
|
316
|
-
availableZatoshi: String(totalAvailable.amount), totalZatoshi: String(totalTotal.amount)
|
|
317
|
-
)
|
|
318
|
-
resolve(balance.nsDictionary)
|
|
319
|
-
return
|
|
320
|
-
} catch {
|
|
321
|
-
reject("GetShieldedBalanceError", "Error", error)
|
|
322
|
-
}
|
|
323
|
-
} else {
|
|
324
|
-
reject("GetShieldedBalanceError", "Wallet does not exist", genericError)
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
237
|
@objc func rescan(
|
|
330
238
|
_ alias: String, resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
331
239
|
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
@@ -343,6 +251,7 @@ class RNZcash: RCTEventEmitter {
|
|
|
343
251
|
wallet.initializeProcessorState()
|
|
344
252
|
wallet.cancellables.forEach { $0.cancel() }
|
|
345
253
|
wallet.subscribe()
|
|
254
|
+
try await wallet.synchronizer.start()
|
|
346
255
|
resolve(nil)
|
|
347
256
|
case .failure:
|
|
348
257
|
reject("RescanError", "Failed to rescan wallet", genericError)
|
|
@@ -405,7 +314,14 @@ class RNZcash: RCTEventEmitter {
|
|
|
405
314
|
if let wallet = SynchronizerMap[alias] {
|
|
406
315
|
do {
|
|
407
316
|
let unifiedAddress = try await wallet.synchronizer.getUnifiedAddress(accountIndex: 0)
|
|
408
|
-
|
|
317
|
+
let saplingAddress = try await wallet.synchronizer.getSaplingAddress(accountIndex: 0)
|
|
318
|
+
let transparentAddress = try await wallet.synchronizer.getTransparentAddress(accountIndex: 0)
|
|
319
|
+
let addresses: NSDictionary = [
|
|
320
|
+
"unifiedAddress": unifiedAddress.stringEncoded,
|
|
321
|
+
"saplingAddress": saplingAddress.stringEncoded,
|
|
322
|
+
"transparentAddress": transparentAddress.stringEncoded
|
|
323
|
+
]
|
|
324
|
+
resolve(addresses)
|
|
409
325
|
return
|
|
410
326
|
} catch {
|
|
411
327
|
reject("deriveUnifiedAddress", "Failed to derive unified address", error)
|
|
@@ -437,7 +353,7 @@ class RNZcash: RCTEventEmitter {
|
|
|
437
353
|
}
|
|
438
354
|
|
|
439
355
|
override func supportedEvents() -> [String] {
|
|
440
|
-
return ["StatusEvent", "UpdateEvent"]
|
|
356
|
+
return ["BalanceEvent", "StatusEvent", "TransactionEvent", "UpdateEvent"]
|
|
441
357
|
}
|
|
442
358
|
}
|
|
443
359
|
|
|
@@ -450,6 +366,7 @@ class WalletSynchronizer: NSObject {
|
|
|
450
366
|
var restart: Bool
|
|
451
367
|
var processorState: ProcessorState
|
|
452
368
|
var cancellables: [AnyCancellable] = []
|
|
369
|
+
var balances: TotalBalances
|
|
453
370
|
|
|
454
371
|
init(alias: String, initializer: Initializer, emitter: @escaping (String, Any) -> Void) throws {
|
|
455
372
|
self.alias = alias
|
|
@@ -459,12 +376,10 @@ class WalletSynchronizer: NSObject {
|
|
|
459
376
|
self.fullySynced = false
|
|
460
377
|
self.restart = false
|
|
461
378
|
self.processorState = ProcessorState(
|
|
462
|
-
alias: self.alias,
|
|
463
|
-
lastDownloadedHeight: 0,
|
|
464
|
-
lastScannedHeight: 0,
|
|
465
379
|
scanProgress: 0,
|
|
466
380
|
networkBlockHeight: 0
|
|
467
381
|
)
|
|
382
|
+
self.balances = TotalBalances(availableZatoshi: "0", totalZatoshi: "0")
|
|
468
383
|
}
|
|
469
384
|
|
|
470
385
|
public func subscribe() {
|
|
@@ -472,10 +387,25 @@ class WalletSynchronizer: NSObject {
|
|
|
472
387
|
.throttle(for: .seconds(0.3), scheduler: DispatchQueue.main, latest: true)
|
|
473
388
|
.sink(receiveValue: { [weak self] state in self?.updateSyncStatus(event: state) })
|
|
474
389
|
.store(in: &cancellables)
|
|
390
|
+
self.synchronizer.stateStream
|
|
391
|
+
.sink(receiveValue: { [weak self] state in self?.updateProcessorState(event: state) })
|
|
392
|
+
.store(in: &cancellables)
|
|
393
|
+
self.synchronizer.eventStream
|
|
394
|
+
.sink { SynchronizerEvent in
|
|
395
|
+
switch SynchronizerEvent {
|
|
396
|
+
case .minedTransaction(let transaction):
|
|
397
|
+
self.emitTxs(transactions: [transaction])
|
|
398
|
+
case .foundTransactions(let transactions, _):
|
|
399
|
+
self.emitTxs(transactions: transactions)
|
|
400
|
+
default:
|
|
401
|
+
return
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
.store(in: &cancellables)
|
|
475
405
|
}
|
|
476
406
|
|
|
477
407
|
func updateSyncStatus(event: SynchronizerState) {
|
|
478
|
-
|
|
408
|
+
|
|
479
409
|
if !self.fullySynced {
|
|
480
410
|
switch event.internalSyncStatus {
|
|
481
411
|
case .syncing:
|
|
@@ -495,68 +425,104 @@ class WalletSynchronizer: NSObject {
|
|
|
495
425
|
let data: NSDictionary = ["alias": self.alias, "name": self.status]
|
|
496
426
|
emit("StatusEvent", data)
|
|
497
427
|
}
|
|
498
|
-
|
|
499
|
-
updateProcessorState(event: event)
|
|
500
428
|
}
|
|
501
429
|
|
|
502
430
|
func updateProcessorState(event: SynchronizerState) {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
let
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
}
|
|
515
|
-
self.processorState.lastDownloadedHeight = status.progressHeight
|
|
516
|
-
self.processorState.scanProgress = Int(floor(status.progress * 100))
|
|
517
|
-
self.processorState.lastScannedHeight = status.progressHeight
|
|
518
|
-
self.processorState.networkBlockHeight = status.targetHeight
|
|
519
|
-
default:
|
|
520
|
-
return
|
|
521
|
-
}
|
|
522
|
-
} else {
|
|
523
|
-
self.processorState.lastDownloadedHeight = self.synchronizer.latestState.latestScannedHeight
|
|
524
|
-
self.processorState.scanProgress = 100
|
|
525
|
-
self.processorState.lastScannedHeight = self.synchronizer.latestState.latestScannedHeight
|
|
526
|
-
self.processorState.networkBlockHeight = event.latestBlockHeight
|
|
431
|
+
var scanProgress = 0
|
|
432
|
+
|
|
433
|
+
switch event.internalSyncStatus {
|
|
434
|
+
case .syncing(let progress):
|
|
435
|
+
scanProgress = Int(floor(progress * 100))
|
|
436
|
+
case .synced:
|
|
437
|
+
scanProgress = 100
|
|
438
|
+
case .unprepared, .disconnected, .stopped:
|
|
439
|
+
scanProgress = 0
|
|
440
|
+
default:
|
|
441
|
+
return
|
|
527
442
|
}
|
|
528
443
|
|
|
529
|
-
if self.processorState.
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
}
|
|
444
|
+
if (scanProgress == self.processorState.scanProgress && event.latestBlockHeight == self.processorState.networkBlockHeight) { return }
|
|
445
|
+
|
|
446
|
+
self.processorState = ProcessorState(scanProgress: scanProgress, networkBlockHeight: event.latestBlockHeight)
|
|
447
|
+
let data: NSDictionary = ["alias": self.alias, "scanProgress": self.processorState.scanProgress, "networkBlockHeight": self.processorState.networkBlockHeight]
|
|
448
|
+
emit("UpdateEvent", data)
|
|
449
|
+
updateBalanceState(event: event)
|
|
536
450
|
}
|
|
537
451
|
|
|
538
452
|
func initializeProcessorState() {
|
|
539
453
|
self.processorState = ProcessorState(
|
|
540
|
-
alias: self.alias,
|
|
541
|
-
lastDownloadedHeight: 0,
|
|
542
|
-
lastScannedHeight: 0,
|
|
543
454
|
scanProgress: 0,
|
|
544
455
|
networkBlockHeight: 0
|
|
545
456
|
)
|
|
457
|
+
self.balances = TotalBalances(availableZatoshi: "0", totalZatoshi: "0")
|
|
546
458
|
}
|
|
547
|
-
}
|
|
548
459
|
|
|
549
|
-
func
|
|
550
|
-
|
|
551
|
-
|
|
460
|
+
func updateBalanceState(event: SynchronizerState) {
|
|
461
|
+
let transparentBalance = event.transparentBalance
|
|
462
|
+
let shieldedBalance = event.shieldedBalance
|
|
463
|
+
|
|
464
|
+
let availableTransparentBalance = transparentBalance.verified
|
|
465
|
+
let totalTransparentBalance = transparentBalance.total
|
|
466
|
+
|
|
467
|
+
let availableShieldedBalance = shieldedBalance.verified
|
|
468
|
+
let totalShieldedBalance = shieldedBalance.total
|
|
469
|
+
|
|
470
|
+
let availableZatoshi = String((availableShieldedBalance + availableTransparentBalance).amount)
|
|
471
|
+
let totalZatoshi = String((totalShieldedBalance + totalTransparentBalance).amount)
|
|
472
|
+
|
|
473
|
+
if (availableZatoshi == self.balances.availableZatoshi && totalZatoshi == self.balances.totalZatoshi) { return }
|
|
552
474
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
chars.append(hexDigits[Int(byte % 16)])
|
|
475
|
+
self.balances = TotalBalances(availableZatoshi: availableZatoshi, totalZatoshi: totalZatoshi)
|
|
476
|
+
let data: NSDictionary = ["alias": self.alias, "availableZatoshi": self.balances.availableZatoshi, "totalZatoshi": self.balances.totalZatoshi]
|
|
477
|
+
emit("BalanceEvent", data)
|
|
557
478
|
}
|
|
558
479
|
|
|
559
|
-
|
|
480
|
+
func emitTxs(transactions: [ZcashTransaction.Overview]) {
|
|
481
|
+
Task {
|
|
482
|
+
var out: [NSDictionary] = []
|
|
483
|
+
for tx in transactions {
|
|
484
|
+
if (tx.isExpiredUmined ?? false) { continue }
|
|
485
|
+
var confTx = ConfirmedTx(
|
|
486
|
+
minedHeight: tx.minedHeight!,
|
|
487
|
+
rawTransactionId: (tx.rawID.toHexStringTxId()),
|
|
488
|
+
blockTimeInSeconds: Int(tx.blockTime!),
|
|
489
|
+
value: String(describing: abs(tx.value.amount))
|
|
490
|
+
)
|
|
491
|
+
if tx.raw != nil {
|
|
492
|
+
confTx.raw = tx.raw!.hexEncodedString()
|
|
493
|
+
}
|
|
494
|
+
if tx.fee != nil {
|
|
495
|
+
confTx.fee = String(describing: abs(tx.value.amount))
|
|
496
|
+
}
|
|
497
|
+
if tx.isSentTransaction {
|
|
498
|
+
let recipients = await self.synchronizer.getRecipients(for: tx)
|
|
499
|
+
if recipients.count > 0 {
|
|
500
|
+
let addresses = recipients.compactMap {
|
|
501
|
+
if case let .address(address) = $0 {
|
|
502
|
+
return address
|
|
503
|
+
} else {
|
|
504
|
+
return nil
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if addresses.count > 0 {
|
|
508
|
+
confTx.toAddress = addresses.first!.stringEncoded
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if tx.memoCount > 0 {
|
|
513
|
+
let memos = (try? await self.synchronizer.getMemos(for: tx)) ?? []
|
|
514
|
+
let textMemos = memos.compactMap {
|
|
515
|
+
return $0.toString()
|
|
516
|
+
}
|
|
517
|
+
confTx.memos = textMemos
|
|
518
|
+
}
|
|
519
|
+
out.append(confTx.nsDictionary)
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
let data: NSDictionary = ["alias": self.alias, "transactions": NSArray(array: out)]
|
|
523
|
+
emit("TransactionEvent", data)
|
|
524
|
+
}
|
|
525
|
+
}
|
|
560
526
|
}
|
|
561
527
|
|
|
562
528
|
// Local file helper funcs
|
|
@@ -596,3 +562,11 @@ func fsBlockDbRootURLHelper(_ alias: String, _ network: ZcashNetwork) throws ->
|
|
|
596
562
|
isDirectory: true
|
|
597
563
|
)
|
|
598
564
|
}
|
|
565
|
+
|
|
566
|
+
func generalStorageURLHelper(_ alias: String, _ network: ZcashNetwork) throws -> URL {
|
|
567
|
+
try documentsDirectoryHelper()
|
|
568
|
+
.appendingPathComponent(
|
|
569
|
+
network.constants.defaultDbNamePrefix + alias + "general_storage",
|
|
570
|
+
isDirectory: true
|
|
571
|
+
)
|
|
572
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Action.swift
|
|
3
|
+
//
|
|
4
|
+
//
|
|
5
|
+
// Created by Michal Fousek on 05.05.2023.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
protocol ActionContext {
|
|
11
|
+
var state: CBPState { get async }
|
|
12
|
+
var prevState: CBPState? { get async }
|
|
13
|
+
var syncControlData: SyncControlData { get async }
|
|
14
|
+
var requestedRewindHeight: BlockHeight? { get async }
|
|
15
|
+
var processedHeight: BlockHeight { get async }
|
|
16
|
+
var lastChainTipUpdateTime: TimeInterval { get async }
|
|
17
|
+
var lastScannedHeight: BlockHeight? { get async }
|
|
18
|
+
var lastEnhancedHeight: BlockHeight? { get async }
|
|
19
|
+
|
|
20
|
+
func update(state: CBPState) async
|
|
21
|
+
func update(syncControlData: SyncControlData) async
|
|
22
|
+
func update(processedHeight: BlockHeight) async
|
|
23
|
+
func update(lastChainTipUpdateTime: TimeInterval) async
|
|
24
|
+
func update(lastScannedHeight: BlockHeight) async
|
|
25
|
+
func update(lastDownloadedHeight: BlockHeight) async
|
|
26
|
+
func update(lastEnhancedHeight: BlockHeight?) async
|
|
27
|
+
func update(requestedRewindHeight: BlockHeight) async
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
actor ActionContextImpl: ActionContext {
|
|
31
|
+
var state: CBPState
|
|
32
|
+
var prevState: CBPState?
|
|
33
|
+
var syncControlData: SyncControlData
|
|
34
|
+
var requestedRewindHeight: BlockHeight?
|
|
35
|
+
/// Amount of blocks that have been processed so far
|
|
36
|
+
var processedHeight: BlockHeight = 0
|
|
37
|
+
/// Update chain tip must be called repeatadly, this value stores the previous update and help to decide when to call it again
|
|
38
|
+
var lastChainTipUpdateTime: TimeInterval = 0.0
|
|
39
|
+
var lastScannedHeight: BlockHeight?
|
|
40
|
+
var lastDownloadedHeight: BlockHeight?
|
|
41
|
+
var lastEnhancedHeight: BlockHeight?
|
|
42
|
+
|
|
43
|
+
init(state: CBPState) {
|
|
44
|
+
self.state = state
|
|
45
|
+
syncControlData = SyncControlData.empty
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
func update(state: CBPState) async {
|
|
49
|
+
prevState = self.state
|
|
50
|
+
self.state = state
|
|
51
|
+
}
|
|
52
|
+
func update(syncControlData: SyncControlData) async { self.syncControlData = syncControlData }
|
|
53
|
+
func update(processedHeight: BlockHeight) async { self.processedHeight = processedHeight }
|
|
54
|
+
func update(lastChainTipUpdateTime: TimeInterval) async { self.lastChainTipUpdateTime = lastChainTipUpdateTime }
|
|
55
|
+
func update(lastScannedHeight: BlockHeight) async { self.lastScannedHeight = lastScannedHeight }
|
|
56
|
+
func update(lastDownloadedHeight: BlockHeight) async { self.lastDownloadedHeight = lastDownloadedHeight }
|
|
57
|
+
func update(lastEnhancedHeight: BlockHeight?) async { self.lastEnhancedHeight = lastEnhancedHeight }
|
|
58
|
+
func update(requestedRewindHeight: BlockHeight) async { self.requestedRewindHeight = requestedRewindHeight }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
enum CBPState: CaseIterable {
|
|
62
|
+
case idle
|
|
63
|
+
case migrateLegacyCacheDB
|
|
64
|
+
case validateServer
|
|
65
|
+
case updateSubtreeRoots
|
|
66
|
+
case updateChainTip
|
|
67
|
+
case processSuggestedScanRanges
|
|
68
|
+
case rewind
|
|
69
|
+
case download
|
|
70
|
+
case scan
|
|
71
|
+
case clearAlreadyScannedBlocks
|
|
72
|
+
case enhance
|
|
73
|
+
case fetchUTXO
|
|
74
|
+
case handleSaplingParams
|
|
75
|
+
case clearCache
|
|
76
|
+
case finished
|
|
77
|
+
case failed
|
|
78
|
+
case stopped
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
protocol Action {
|
|
82
|
+
/// If this is true and action fails with error then blocks cache is cleared.
|
|
83
|
+
var removeBlocksCacheWhenFailed: Bool { get }
|
|
84
|
+
|
|
85
|
+
// When any action is created it can get `DIContainer` and resolve any depedencies it requires.
|
|
86
|
+
// Every action uses `context` to get some informartion like download range.
|
|
87
|
+
//
|
|
88
|
+
// `didUpdate` is closure that action use to tell CBP that some part of the work is done. For example if download action would like to
|
|
89
|
+
// update progress on every block downloaded it can use this closure. Also if action doesn't need to update progress on partial work it doesn't
|
|
90
|
+
// need to use this closure at all.
|
|
91
|
+
//
|
|
92
|
+
// Each action updates context accordingly. It should at least set new state. Reason for this is that action can return different states for
|
|
93
|
+
// different conditions. And action is the thing that knows these conditions.
|
|
94
|
+
func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext
|
|
95
|
+
|
|
96
|
+
// Should be called on each existing action when processor wants to stop. Some actions may do it's own background work.
|
|
97
|
+
func stop() async
|
|
98
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ClearCacheForLastScannedBatch.swift
|
|
3
|
+
//
|
|
4
|
+
//
|
|
5
|
+
// Created by Michal Fousek on 08.05.2023.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
final class ClearAlreadyScannedBlocksAction {
|
|
11
|
+
let storage: CompactBlockRepository
|
|
12
|
+
let transactionRepository: TransactionRepository
|
|
13
|
+
|
|
14
|
+
init(container: DIContainer) {
|
|
15
|
+
storage = container.resolve(CompactBlockRepository.self)
|
|
16
|
+
transactionRepository = container.resolve(TransactionRepository.self)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
extension ClearAlreadyScannedBlocksAction: Action {
|
|
21
|
+
var removeBlocksCacheWhenFailed: Bool { false }
|
|
22
|
+
|
|
23
|
+
func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
|
|
24
|
+
guard let lastScannedHeight = await context.lastScannedHeight else {
|
|
25
|
+
throw ZcashError.compactBlockProcessorLastScannedHeight
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try await storage.clear(upTo: lastScannedHeight)
|
|
29
|
+
|
|
30
|
+
await context.update(state: .enhance)
|
|
31
|
+
return context
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func stop() async { }
|
|
35
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ClearCacheAction.swift
|
|
3
|
+
//
|
|
4
|
+
//
|
|
5
|
+
// Created by Michal Fousek on 05.05.2023.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
final class ClearCacheAction {
|
|
11
|
+
let storage: CompactBlockRepository
|
|
12
|
+
|
|
13
|
+
init(container: DIContainer) {
|
|
14
|
+
storage = container.resolve(CompactBlockRepository.self)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
extension ClearCacheAction: Action {
|
|
19
|
+
var removeBlocksCacheWhenFailed: Bool { false }
|
|
20
|
+
|
|
21
|
+
func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
|
|
22
|
+
try await storage.clear()
|
|
23
|
+
|
|
24
|
+
await context.update(state: .processSuggestedScanRanges)
|
|
25
|
+
|
|
26
|
+
return context
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
func stop() async { }
|
|
30
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
//
|
|
2
|
+
// DownloadAction.swift
|
|
3
|
+
//
|
|
4
|
+
//
|
|
5
|
+
// Created by Michal Fousek on 05.05.2023.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
final class DownloadAction {
|
|
11
|
+
let configProvider: CompactBlockProcessor.ConfigProvider
|
|
12
|
+
let downloader: BlockDownloader
|
|
13
|
+
let transactionRepository: TransactionRepository
|
|
14
|
+
let logger: Logger
|
|
15
|
+
|
|
16
|
+
init(container: DIContainer, configProvider: CompactBlockProcessor.ConfigProvider) {
|
|
17
|
+
self.configProvider = configProvider
|
|
18
|
+
downloader = container.resolve(BlockDownloader.self)
|
|
19
|
+
transactionRepository = container.resolve(TransactionRepository.self)
|
|
20
|
+
logger = container.resolve(Logger.self)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private func update(context: ActionContext) async -> ActionContext {
|
|
24
|
+
await context.update(state: .scan)
|
|
25
|
+
return context
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
extension DownloadAction: Action {
|
|
30
|
+
var removeBlocksCacheWhenFailed: Bool { true }
|
|
31
|
+
|
|
32
|
+
func run(with context: ActionContext, didUpdate: @escaping (CompactBlockProcessor.Event) async -> Void) async throws -> ActionContext {
|
|
33
|
+
guard let lastScannedHeight = await context.lastScannedHeight else {
|
|
34
|
+
return await update(context: context)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let config = await configProvider.config
|
|
38
|
+
let latestBlockHeight = await context.syncControlData.latestBlockHeight
|
|
39
|
+
// This action is executed for each batch (batch size is 100 blocks by default) until all the blocks in whole `downloadRange` are downloaded.
|
|
40
|
+
// So the right range for this batch must be computed.
|
|
41
|
+
let batchRangeStart = lastScannedHeight
|
|
42
|
+
let batchRangeEnd = min(latestBlockHeight, batchRangeStart + config.batchSize)
|
|
43
|
+
|
|
44
|
+
guard batchRangeStart <= batchRangeEnd else {
|
|
45
|
+
return await update(context: context)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let batchRange = batchRangeStart...batchRangeEnd
|
|
49
|
+
let potentialDownloadLimit = batchRange.upperBound + (2 * config.batchSize)
|
|
50
|
+
let downloadLimit = await context.syncControlData.latestBlockHeight >= potentialDownloadLimit ? potentialDownloadLimit : batchRangeEnd
|
|
51
|
+
|
|
52
|
+
logger.debug("Starting download with range: \(batchRangeStart)...\(batchRangeEnd)")
|
|
53
|
+
|
|
54
|
+
await downloader.update(latestDownloadedBlockHeight: batchRangeStart, force: true)
|
|
55
|
+
try await downloader.setSyncRange(lastScannedHeight...latestBlockHeight, batchSize: config.batchSize)
|
|
56
|
+
await downloader.setDownloadLimit(downloadLimit)
|
|
57
|
+
await downloader.startDownload(maxBlockBufferSize: config.downloadBufferSize)
|
|
58
|
+
|
|
59
|
+
try await downloader.waitUntilRequestedBlocksAreDownloaded(in: batchRange)
|
|
60
|
+
|
|
61
|
+
return await update(context: context)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
func stop() async {
|
|
65
|
+
await downloader.stopDownload()
|
|
66
|
+
}
|
|
67
|
+
}
|