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
@@ -9,6 +9,8 @@
9
9
  import Foundation
10
10
 
11
11
 
12
+ let globalDBLock = NSLock()
13
+
12
14
  actor ZcashRustBackend: ZcashRustBackendWelding {
13
15
  let minimumConfirmations: UInt32 = 10
14
16
  let useZIP317Fees = false
@@ -21,6 +23,7 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
21
23
 
22
24
  nonisolated let networkType: NetworkType
23
25
 
26
+ static var tracingEnabled = false
24
27
  /// Creates instance of `ZcashRustBackend`.
25
28
  /// - Parameters:
26
29
  /// - dbData: `URL` pointing to file where data database will be.
@@ -30,23 +33,43 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
30
33
  /// - spendParamsPath: `URL` pointing to spend parameters file.
31
34
  /// - outputParamsPath: `URL` pointing to output parameters file.
32
35
  /// - networkType: Network type to use.
33
- init(dbData: URL, fsBlockDbRoot: URL, spendParamsPath: URL, outputParamsPath: URL, networkType: NetworkType) {
36
+ /// - enableTracing: this sets up whether the tracing system will dump logs onto the OSLogger system or not.
37
+ /// **Important note:** this will enable the tracing **for all instances** of ZcashRustBackend, not only for this one.
38
+ init(dbData: URL, fsBlockDbRoot: URL, spendParamsPath: URL, outputParamsPath: URL, networkType: NetworkType, enableTracing: Bool = false) {
34
39
  self.dbData = dbData.osStr()
35
40
  self.fsBlockDbRoot = fsBlockDbRoot.osPathStr()
36
41
  self.spendParamsPath = spendParamsPath.osPathStr()
37
42
  self.outputParamsPath = outputParamsPath.osPathStr()
38
43
  self.networkType = networkType
39
44
  self.keyDeriving = ZcashKeyDerivationBackend(networkType: networkType)
45
+
46
+ if enableTracing && !Self.tracingEnabled {
47
+ Self.tracingEnabled = true
48
+ Self.enableTracing()
49
+ }
40
50
  }
41
51
 
42
- func createAccount(seed: [UInt8]) async throws -> UnifiedSpendingKey {
52
+ func createAccount(seed: [UInt8], treeState: TreeState, recoverUntil: UInt32?) async throws -> UnifiedSpendingKey {
53
+ var rUntil: Int64 = -1
54
+
55
+ if let recoverUntil {
56
+ rUntil = Int64(recoverUntil)
57
+ }
58
+
59
+ let treeStateBytes = try treeState.serializedData(partial: false).bytes
60
+
61
+ globalDBLock.lock()
43
62
  let ffiBinaryKeyPtr = zcashlc_create_account(
44
63
  dbData.0,
45
64
  dbData.1,
46
65
  seed,
47
66
  UInt(seed.count),
67
+ treeStateBytes,
68
+ UInt(treeStateBytes.count),
69
+ rUntil,
48
70
  networkType.networkId
49
71
  )
72
+ globalDBLock.unlock()
50
73
 
51
74
  guard let ffiBinaryKeyPtr else {
52
75
  throw ZcashError.rustCreateAccount(lastErrorMessage(fallback: "`createAccount` failed with unknown error"))
@@ -62,34 +85,44 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
62
85
  to address: String,
63
86
  value: Int64,
64
87
  memo: MemoBytes?
65
- ) async throws -> Int64 {
66
- let result = usk.bytes.withUnsafeBufferPointer { uskPtr in
67
- zcashlc_create_to_address(
68
- dbData.0,
69
- dbData.1,
70
- uskPtr.baseAddress,
71
- UInt(usk.bytes.count),
72
- [CChar](address.utf8CString),
73
- value,
74
- memo?.bytes,
75
- spendParamsPath.0,
76
- spendParamsPath.1,
77
- outputParamsPath.0,
78
- outputParamsPath.1,
79
- networkType.networkId,
80
- minimumConfirmations,
81
- useZIP317Fees
82
- )
88
+ ) async throws -> Data {
89
+ var contiguousTxIdBytes = ContiguousArray<UInt8>([UInt8](repeating: 0x0, count: 32))
90
+
91
+ globalDBLock.lock()
92
+ let success = contiguousTxIdBytes.withUnsafeMutableBufferPointer { txIdBytePtr in
93
+ usk.bytes.withUnsafeBufferPointer { uskPtr in
94
+ zcashlc_create_to_address(
95
+ dbData.0,
96
+ dbData.1,
97
+ uskPtr.baseAddress,
98
+ UInt(usk.bytes.count),
99
+ [CChar](address.utf8CString),
100
+ value,
101
+ memo?.bytes,
102
+ spendParamsPath.0,
103
+ spendParamsPath.1,
104
+ outputParamsPath.0,
105
+ outputParamsPath.1,
106
+ networkType.networkId,
107
+ minimumConfirmations,
108
+ useZIP317Fees,
109
+ txIdBytePtr.baseAddress
110
+ )
111
+ }
83
112
  }
113
+ globalDBLock.unlock()
84
114
 
85
- guard result > 0 else {
115
+ guard success else {
86
116
  throw ZcashError.rustCreateToAddress(lastErrorMessage(fallback: "`createToAddress` failed with unknown error"))
87
117
  }
88
118
 
89
- return result
119
+ return contiguousTxIdBytes.withUnsafeBufferPointer { txIdBytePtr in
120
+ Data(txIdBytePtr)
121
+ }
90
122
  }
91
123
 
92
124
  func decryptAndStoreTransaction(txBytes: [UInt8], minedHeight: Int32) async throws {
125
+ globalDBLock.lock()
93
126
  let result = zcashlc_decrypt_and_store_transaction(
94
127
  dbData.0,
95
128
  dbData.1,
@@ -98,6 +131,7 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
98
131
  UInt32(minedHeight),
99
132
  networkType.networkId
100
133
  )
134
+ globalDBLock.unlock()
101
135
 
102
136
  guard result != 0 else {
103
137
  throw ZcashError.rustDecryptAndStoreTransaction(lastErrorMessage(fallback: "`decryptAndStoreTransaction` failed with unknown error"))
@@ -105,7 +139,9 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
105
139
  }
106
140
 
107
141
  func getBalance(account: Int32) async throws -> Int64 {
142
+ globalDBLock.lock()
108
143
  let balance = zcashlc_get_balance(dbData.0, dbData.1, account, networkType.networkId)
144
+ globalDBLock.unlock()
109
145
 
110
146
  guard balance >= 0 else {
111
147
  throw ZcashError.rustGetBalance(Int(account), lastErrorMessage(fallback: "Error getting total balance from account \(account)"))
@@ -115,12 +151,14 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
115
151
  }
116
152
 
117
153
  func getCurrentAddress(account: Int32) async throws -> UnifiedAddress {
154
+ globalDBLock.lock()
118
155
  let addressCStr = zcashlc_get_current_address(
119
156
  dbData.0,
120
157
  dbData.1,
121
158
  account,
122
159
  networkType.networkId
123
160
  )
161
+ globalDBLock.unlock()
124
162
 
125
163
  guard let addressCStr else {
126
164
  throw ZcashError.rustGetCurrentAddress(lastErrorMessage(fallback: "`getCurrentAddress` failed with unknown error"))
@@ -136,12 +174,14 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
136
174
  }
137
175
 
138
176
  func getNearestRewindHeight(height: Int32) async throws -> Int32 {
177
+ globalDBLock.lock()
139
178
  let result = zcashlc_get_nearest_rewind_height(
140
179
  dbData.0,
141
180
  dbData.1,
142
181
  height,
143
182
  networkType.networkId
144
183
  )
184
+ globalDBLock.unlock()
145
185
 
146
186
  guard result > 0 else {
147
187
  throw ZcashError.rustGetNearestRewindHeight(lastErrorMessage(fallback: "`getNearestRewindHeight` failed with unknown error"))
@@ -151,12 +191,14 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
151
191
  }
152
192
 
153
193
  func getNextAvailableAddress(account: Int32) async throws -> UnifiedAddress {
194
+ globalDBLock.lock()
154
195
  let addressCStr = zcashlc_get_next_available_address(
155
196
  dbData.0,
156
197
  dbData.1,
157
198
  account,
158
199
  networkType.networkId
159
200
  )
201
+ globalDBLock.unlock()
160
202
 
161
203
  guard let addressCStr else {
162
204
  throw ZcashError.rustGetNextAvailableAddress(lastErrorMessage(fallback: "`getNextAvailableAddress` failed with unknown error"))
@@ -171,26 +213,19 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
171
213
  return UnifiedAddress(validatedEncoding: address, networkType: networkType)
172
214
  }
173
215
 
174
- func getReceivedMemo(idNote: Int64) async -> Memo? {
175
- var contiguousMemoBytes = ContiguousArray<UInt8>(MemoBytes.empty().bytes)
176
- var success = false
177
-
178
- contiguousMemoBytes.withUnsafeMutableBufferPointer { memoBytePtr in
179
- success = zcashlc_get_received_memo(dbData.0, dbData.1, idNote, memoBytePtr.baseAddress, networkType.networkId)
216
+ func getMemo(txId: Data, outputIndex: UInt16) async throws -> Memo? {
217
+ guard txId.count == 32 else {
218
+ throw ZcashError.rustGetMemoInvalidTxIdLength
180
219
  }
181
220
 
182
- guard success else { return nil }
183
-
184
- return (try? MemoBytes(contiguousBytes: contiguousMemoBytes)).flatMap { try? $0.intoMemo() }
185
- }
186
-
187
- func getSentMemo(idNote: Int64) async -> Memo? {
188
221
  var contiguousMemoBytes = ContiguousArray<UInt8>(MemoBytes.empty().bytes)
189
222
  var success = false
190
223
 
191
- contiguousMemoBytes.withUnsafeMutableBytes { memoBytePtr in
192
- success = zcashlc_get_sent_memo(dbData.0, dbData.1, idNote, memoBytePtr.baseAddress, networkType.networkId)
224
+ globalDBLock.lock()
225
+ contiguousMemoBytes.withUnsafeMutableBufferPointer { memoBytePtr in
226
+ success = zcashlc_get_memo(dbData.0, dbData.1, txId.bytes, outputIndex, memoBytePtr.baseAddress, networkType.networkId)
193
227
  }
228
+ globalDBLock.unlock()
194
229
 
195
230
  guard success else { return nil }
196
231
 
@@ -202,12 +237,14 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
202
237
  throw ZcashError.rustGetTransparentBalanceNegativeAccount(Int(account))
203
238
  }
204
239
 
240
+ globalDBLock.lock()
205
241
  let balance = zcashlc_get_total_transparent_balance_for_account(
206
242
  dbData.0,
207
243
  dbData.1,
208
244
  networkType.networkId,
209
245
  account
210
246
  )
247
+ globalDBLock.unlock()
211
248
 
212
249
  guard balance >= 0 else {
213
250
  throw ZcashError.rustGetTransparentBalance(
@@ -220,6 +257,7 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
220
257
  }
221
258
 
222
259
  func getVerifiedBalance(account: Int32) async throws -> Int64 {
260
+ globalDBLock.lock()
223
261
  let balance = zcashlc_get_verified_balance(
224
262
  dbData.0,
225
263
  dbData.1,
@@ -227,6 +265,7 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
227
265
  networkType.networkId,
228
266
  minimumConfirmations
229
267
  )
268
+ globalDBLock.unlock()
230
269
 
231
270
  guard balance >= 0 else {
232
271
  throw ZcashError.rustGetVerifiedBalance(
@@ -243,6 +282,7 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
243
282
  throw ZcashError.rustGetVerifiedTransparentBalanceNegativeAccount(Int(account))
244
283
  }
245
284
 
285
+ globalDBLock.lock()
246
286
  let balance = zcashlc_get_verified_transparent_balance_for_account(
247
287
  dbData.0,
248
288
  dbData.1,
@@ -250,6 +290,7 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
250
290
  account,
251
291
  minimumConfirmations
252
292
  )
293
+ globalDBLock.unlock()
253
294
 
254
295
  guard balance >= 0 else {
255
296
  throw ZcashError.rustGetVerifiedTransparentBalance(
@@ -262,7 +303,11 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
262
303
  }
263
304
 
264
305
  func initDataDb(seed: [UInt8]?) async throws -> DbInitResult {
265
- switch zcashlc_init_data_database(dbData.0, dbData.1, seed, UInt(seed?.count ?? 0), networkType.networkId) {
306
+ globalDBLock.lock()
307
+ let initResult = zcashlc_init_data_database(dbData.0, dbData.1, seed, UInt(seed?.count ?? 0), networkType.networkId)
308
+ globalDBLock.unlock()
309
+
310
+ switch initResult {
266
311
  case 0: // ok
267
312
  return DbInitResult.success
268
313
  case 1:
@@ -272,59 +317,10 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
272
317
  }
273
318
  }
274
319
 
275
- func initAccountsTable(ufvks: [UnifiedFullViewingKey]) async throws {
276
- var ffiUfvks: [FFIEncodedKey] = []
277
- for ufvk in ufvks {
278
- guard !ufvk.encoding.containsCStringNullBytesBeforeStringEnding() else {
279
- throw ZcashError.rustInitAccountsTableViewingKeyCotainsNullBytes
280
- }
281
-
282
- guard self.keyDeriving.isValidUnifiedFullViewingKey(ufvk.encoding) else {
283
- throw ZcashError.rustInitAccountsTableViewingKeyIsInvalid
284
- }
285
-
286
- let ufvkCStr = [CChar](String(ufvk.encoding).utf8CString)
287
-
288
- let ufvkPtr = UnsafeMutablePointer<CChar>.allocate(capacity: ufvkCStr.count)
289
- ufvkPtr.initialize(from: ufvkCStr, count: ufvkCStr.count)
290
-
291
- ffiUfvks.append(
292
- FFIEncodedKey(account_id: ufvk.account, encoding: ufvkPtr)
293
- )
294
- }
295
-
296
- var contiguousUVKs = ContiguousArray(ffiUfvks)
297
-
298
- var result = false
299
-
300
- contiguousUVKs.withContiguousMutableStorageIfAvailable { ufvksPtr in
301
- result = zcashlc_init_accounts_table_with_keys(
302
- dbData.0,
303
- dbData.1,
304
- ufvksPtr.baseAddress,
305
- UInt(ufvks.count),
306
- networkType.networkId
307
- )
308
- }
309
-
310
- defer {
311
- for ufvk in ffiUfvks {
312
- ufvk.encoding.deallocate()
313
- }
314
- }
315
-
316
- guard result else {
317
- let message = lastErrorMessage(fallback: "`initAccountsTable` failed with unknown error")
318
- if message.isDbNotEmptyErrorMessage() {
319
- throw ZcashError.rustInitAccountsTableDataDbNotEmpty
320
- } else {
321
- throw ZcashError.rustInitAccountsTable(message)
322
- }
323
- }
324
- }
325
-
326
320
  func initBlockMetadataDb() async throws {
321
+ globalDBLock.lock()
327
322
  let result = zcashlc_init_block_metadata_db(fsBlockDbRoot.0, fsBlockDbRoot.1)
323
+ globalDBLock.unlock()
328
324
 
329
325
  guard result else {
330
326
  throw ZcashError.rustInitBlockMetadataDb(lastErrorMessage(fallback: "`initBlockMetadataDb` failed with unknown error"))
@@ -380,7 +376,9 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
380
376
 
381
377
  fsBlocks.initialize(to: meta)
382
378
 
379
+ globalDBLock.lock()
383
380
  let res = zcashlc_write_block_metadata(fsBlockDbRoot.0, fsBlockDbRoot.1, fsBlocks)
381
+ globalDBLock.unlock()
384
382
 
385
383
  guard res else {
386
384
  throw ZcashError.rustWriteBlocksMetadata(lastErrorMessage(fallback: "`writeBlocksMetadata` failed with unknown error"))
@@ -388,51 +386,29 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
388
386
  }
389
387
  }
390
388
 
391
- func initBlocksTable(
392
- height: Int32,
393
- hash: String,
394
- time: UInt32,
395
- saplingTree: String
396
- ) async throws {
397
- guard !hash.containsCStringNullBytesBeforeStringEnding() else {
398
- throw ZcashError.rustInitBlocksTableHashContainsNullBytes
399
- }
389
+ func latestCachedBlockHeight() async throws -> BlockHeight {
390
+ globalDBLock.lock()
391
+ let height = zcashlc_latest_cached_block_height(fsBlockDbRoot.0, fsBlockDbRoot.1)
392
+ globalDBLock.unlock()
400
393
 
401
- guard !saplingTree.containsCStringNullBytesBeforeStringEnding() else {
402
- throw ZcashError.rustInitBlocksTableSaplingTreeContainsNullBytes
403
- }
404
-
405
- let result = zcashlc_init_blocks_table(
406
- dbData.0,
407
- dbData.1,
408
- height,
409
- [CChar](hash.utf8CString),
410
- time,
411
- [CChar](saplingTree.utf8CString),
412
- networkType.networkId
413
- )
414
-
415
- guard result != 0 else {
416
- let message = lastErrorMessage(fallback: "`initBlocksTable` failed with unknown error")
417
- if message.isDbNotEmptyErrorMessage() {
418
- throw ZcashError.rustInitBlocksTableDataDbNotEmpty
419
- } else {
420
- throw ZcashError.rustInitBlocksTable(message)
421
- }
394
+ if height >= 0 {
395
+ return BlockHeight(height)
396
+ } else if height == -1 {
397
+ return BlockHeight.empty()
398
+ } else {
399
+ throw ZcashError.rustLatestCachedBlockHeight(lastErrorMessage(fallback: "`latestCachedBlockHeight` failed with unknown error"))
422
400
  }
423
401
  }
424
402
 
425
- func latestCachedBlockHeight() async -> BlockHeight {
426
- return BlockHeight(zcashlc_latest_cached_block_height(fsBlockDbRoot.0, fsBlockDbRoot.1))
427
- }
428
-
429
403
  func listTransparentReceivers(account: Int32) async throws -> [TransparentAddress] {
404
+ globalDBLock.lock()
430
405
  let encodedKeysPtr = zcashlc_list_transparent_receivers(
431
406
  dbData.0,
432
407
  dbData.1,
433
408
  account,
434
409
  networkType.networkId
435
410
  )
411
+ globalDBLock.unlock()
436
412
 
437
413
  guard let encodedKeysPtr else {
438
414
  throw ZcashError.rustListTransparentReceivers(lastErrorMessage(fallback: "`listTransparentReceivers` failed with unknown error"))
@@ -464,6 +440,7 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
464
440
  value: Int64,
465
441
  height: BlockHeight
466
442
  ) async throws {
443
+ globalDBLock.lock()
467
444
  let result = zcashlc_put_utxo(
468
445
  dbData.0,
469
446
  dbData.1,
@@ -476,29 +453,17 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
476
453
  Int32(height),
477
454
  networkType.networkId
478
455
  )
456
+ globalDBLock.unlock()
479
457
 
480
458
  guard result else {
481
459
  throw ZcashError.rustPutUnspentTransparentOutput(lastErrorMessage(fallback: "`putUnspentTransparentOutput` failed with unknown error"))
482
460
  }
483
461
  }
484
462
 
485
- func validateCombinedChain(limit: UInt32 = 0) async throws {
486
- let result = zcashlc_validate_combined_chain(fsBlockDbRoot.0, fsBlockDbRoot.1, dbData.0, dbData.1, limit, networkType.networkId)
487
-
488
- switch result {
489
- case -1:
490
- return
491
- case 0:
492
- throw ZcashError.rustValidateCombinedChainValidationFailed(
493
- lastErrorMessage(fallback: "`validateCombinedChain` failed with unknown error")
494
- )
495
- default:
496
- throw ZcashError.rustValidateCombinedChainInvalidChain(result)
497
- }
498
- }
499
-
500
463
  func rewindToHeight(height: Int32) async throws {
464
+ globalDBLock.lock()
501
465
  let result = zcashlc_rewind_to_height(dbData.0, dbData.1, height, networkType.networkId)
466
+ globalDBLock.unlock()
502
467
 
503
468
  guard result else {
504
469
  throw ZcashError.rustRewindToHeight(height, lastErrorMessage(fallback: "`rewindToHeight` failed with unknown error"))
@@ -506,15 +471,162 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
506
471
  }
507
472
 
508
473
  func rewindCacheToHeight(height: Int32) async throws {
474
+ globalDBLock.lock()
509
475
  let result = zcashlc_rewind_fs_block_cache_to_height(fsBlockDbRoot.0, fsBlockDbRoot.1, height)
476
+ globalDBLock.unlock()
510
477
 
511
478
  guard result else {
512
479
  throw ZcashError.rustRewindCacheToHeight(lastErrorMessage(fallback: "`rewindCacheToHeight` failed with unknown error"))
513
480
  }
514
481
  }
515
482
 
516
- func scanBlocks(limit: UInt32 = 0) async throws {
517
- let result = zcashlc_scan_blocks(fsBlockDbRoot.0, fsBlockDbRoot.1, dbData.0, dbData.1, limit, networkType.networkId)
483
+ func putSaplingSubtreeRoots(startIndex: UInt64, roots: [SubtreeRoot]) async throws {
484
+ var ffiSubtreeRootsVec: [FfiSubtreeRoot] = []
485
+
486
+ for root in roots {
487
+ let hashPtr = UnsafeMutablePointer<UInt8>.allocate(capacity: root.rootHash.count)
488
+
489
+ let contiguousHashBytes = ContiguousArray(root.rootHash.bytes)
490
+
491
+ let result: Void? = contiguousHashBytes.withContiguousStorageIfAvailable { hashBytesPtr in
492
+ // swiftlint:disable:next force_unwrapping
493
+ hashPtr.initialize(from: hashBytesPtr.baseAddress!, count: hashBytesPtr.count)
494
+ }
495
+
496
+ guard result != nil else {
497
+ defer {
498
+ hashPtr.deallocate()
499
+ ffiSubtreeRootsVec.deallocateElements()
500
+ }
501
+ throw ZcashError.rustPutSaplingSubtreeRootsAllocationProblem
502
+ }
503
+
504
+ ffiSubtreeRootsVec.append(
505
+ FfiSubtreeRoot(
506
+ root_hash_ptr: hashPtr,
507
+ root_hash_ptr_len: UInt(contiguousHashBytes.count),
508
+ completing_block_height: UInt32(root.completingBlockHeight)
509
+ )
510
+ )
511
+ }
512
+
513
+ var contiguousFfiRoots = ContiguousArray(ffiSubtreeRootsVec)
514
+
515
+ let len = UInt(contiguousFfiRoots.count)
516
+
517
+ let rootsPtr = UnsafeMutablePointer<FfiSubtreeRoots>.allocate(capacity: 1)
518
+
519
+ defer {
520
+ ffiSubtreeRootsVec.deallocateElements()
521
+ rootsPtr.deallocate()
522
+ }
523
+
524
+ try contiguousFfiRoots.withContiguousMutableStorageIfAvailable { ptr in
525
+ var roots = FfiSubtreeRoots()
526
+ roots.ptr = ptr.baseAddress
527
+ roots.len = len
528
+
529
+ rootsPtr.initialize(to: roots)
530
+
531
+ globalDBLock.lock()
532
+ let res = zcashlc_put_sapling_subtree_roots(dbData.0, dbData.1, startIndex, rootsPtr, networkType.networkId)
533
+ globalDBLock.unlock()
534
+
535
+ guard res else {
536
+ throw ZcashError.rustPutSaplingSubtreeRoots(lastErrorMessage(fallback: "`putSaplingSubtreeRoots` failed with unknown error"))
537
+ }
538
+ }
539
+ }
540
+
541
+ func updateChainTip(height: Int32) async throws {
542
+ globalDBLock.lock()
543
+ let result = zcashlc_update_chain_tip(dbData.0, dbData.1, height, networkType.networkId)
544
+ globalDBLock.unlock()
545
+
546
+ guard result else {
547
+ throw ZcashError.rustUpdateChainTip(lastErrorMessage(fallback: "`updateChainTip` failed with unknown error"))
548
+ }
549
+ }
550
+
551
+ func fullyScannedHeight() async throws -> BlockHeight? {
552
+ globalDBLock.lock()
553
+ let height = zcashlc_fully_scanned_height(dbData.0, dbData.1, networkType.networkId)
554
+ globalDBLock.unlock()
555
+
556
+ if height >= 0 {
557
+ return BlockHeight(height)
558
+ } else if height == -1 {
559
+ return nil
560
+ } else {
561
+ throw ZcashError.rustFullyScannedHeight(lastErrorMessage(fallback: "`fullyScannedHeight` failed with unknown error"))
562
+ }
563
+ }
564
+
565
+ func maxScannedHeight() async throws -> BlockHeight? {
566
+ globalDBLock.lock()
567
+ let height = zcashlc_max_scanned_height(dbData.0, dbData.1, networkType.networkId)
568
+ globalDBLock.unlock()
569
+
570
+ if height >= 0 {
571
+ return BlockHeight(height)
572
+ } else if height == -1 {
573
+ return nil
574
+ } else {
575
+ throw ZcashError.rustMaxScannedHeight(lastErrorMessage(fallback: "`maxScannedHeight` failed with unknown error"))
576
+ }
577
+ }
578
+
579
+ func getScanProgress() async throws -> ScanProgress? {
580
+ globalDBLock.lock()
581
+ let result = zcashlc_get_scan_progress(dbData.0, dbData.1, networkType.networkId)
582
+ globalDBLock.unlock()
583
+
584
+ if result.denominator == 0 {
585
+ switch result.numerator {
586
+ case 0:
587
+ return nil
588
+ default:
589
+ throw ZcashError.rustGetScanProgress(lastErrorMessage(fallback: "`getScanProgress` failed with unknown error"))
590
+ }
591
+ } else {
592
+ return ScanProgress(numerator: result.numerator, denominator: result.denominator)
593
+ }
594
+ }
595
+
596
+ func suggestScanRanges() async throws -> [ScanRange] {
597
+ globalDBLock.lock()
598
+ let scanRangesPtr = zcashlc_suggest_scan_ranges(dbData.0, dbData.1, networkType.networkId)
599
+ globalDBLock.unlock()
600
+
601
+ guard let scanRangesPtr else {
602
+ throw ZcashError.rustSuggestScanRanges(lastErrorMessage(fallback: "`suggestScanRanges` failed with unknown error"))
603
+ }
604
+
605
+ defer { zcashlc_free_scan_ranges(scanRangesPtr) }
606
+
607
+ var scanRanges: [ScanRange] = []
608
+
609
+ for i in (0 ..< Int(scanRangesPtr.pointee.len)) {
610
+ let scanRange = scanRangesPtr.pointee.ptr.advanced(by: i).pointee
611
+
612
+ scanRanges.append(
613
+ ScanRange(
614
+ range: Range(uncheckedBounds: (
615
+ BlockHeight(scanRange.start),
616
+ BlockHeight(scanRange.end)
617
+ )),
618
+ priority: ScanRange.Priority(scanRange.priority)
619
+ )
620
+ )
621
+ }
622
+
623
+ return scanRanges
624
+ }
625
+
626
+ func scanBlocks(fromHeight: Int32, limit: UInt32 = 0) async throws {
627
+ globalDBLock.lock()
628
+ let result = zcashlc_scan_blocks(fsBlockDbRoot.0, fsBlockDbRoot.1, dbData.0, dbData.1, fromHeight, limit, networkType.networkId)
629
+ globalDBLock.unlock()
518
630
 
519
631
  guard result != 0 else {
520
632
  throw ZcashError.rustScanBlocks(lastErrorMessage(fallback: "`scanBlocks` failed with unknown error"))
@@ -525,30 +637,39 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
525
637
  usk: UnifiedSpendingKey,
526
638
  memo: MemoBytes?,
527
639
  shieldingThreshold: Zatoshi
528
- ) async throws -> Int64 {
529
- let result = usk.bytes.withUnsafeBufferPointer { uskBuffer in
530
- zcashlc_shield_funds(
531
- dbData.0,
532
- dbData.1,
533
- uskBuffer.baseAddress,
534
- UInt(usk.bytes.count),
535
- memo?.bytes,
536
- UInt64(shieldingThreshold.amount),
537
- spendParamsPath.0,
538
- spendParamsPath.1,
539
- outputParamsPath.0,
540
- outputParamsPath.1,
541
- networkType.networkId,
542
- minimumConfirmations,
543
- useZIP317Fees
544
- )
640
+ ) async throws -> Data {
641
+ var contiguousTxIdBytes = ContiguousArray<UInt8>([UInt8](repeating: 0x0, count: 32))
642
+
643
+ globalDBLock.lock()
644
+ let success = contiguousTxIdBytes.withUnsafeMutableBufferPointer { txIdBytePtr in
645
+ usk.bytes.withUnsafeBufferPointer { uskBuffer in
646
+ zcashlc_shield_funds(
647
+ dbData.0,
648
+ dbData.1,
649
+ uskBuffer.baseAddress,
650
+ UInt(usk.bytes.count),
651
+ memo?.bytes,
652
+ UInt64(shieldingThreshold.amount),
653
+ spendParamsPath.0,
654
+ spendParamsPath.1,
655
+ outputParamsPath.0,
656
+ outputParamsPath.1,
657
+ networkType.networkId,
658
+ minimumConfirmations,
659
+ useZIP317Fees,
660
+ txIdBytePtr.baseAddress
661
+ )
662
+ }
545
663
  }
664
+ globalDBLock.unlock()
546
665
 
547
- guard result > 0 else {
666
+ guard success else {
548
667
  throw ZcashError.rustShieldFunds(lastErrorMessage(fallback: "`shieldFunds` failed with unknown error"))
549
668
  }
550
669
 
551
- return result
670
+ return contiguousTxIdBytes.withUnsafeBufferPointer { txIdBytePtr in
671
+ Data(txIdBytePtr)
672
+ }
552
673
  }
553
674
 
554
675
  nonisolated func consensusBranchIdFor(height: Int32) throws -> Int32 {
@@ -562,6 +683,12 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
562
683
  }
563
684
  }
564
685
 
686
+ private extension ZcashRustBackend {
687
+ static func enableTracing() {
688
+ zcashlc_init_on_load(false)
689
+ }
690
+ }
691
+
565
692
  private extension ZcashRustBackend {
566
693
  nonisolated func lastErrorMessage(fallback: String) -> String {
567
694
  let errorLen = zcashlc_last_error_length()
@@ -643,3 +770,11 @@ extension Array where Element == FFIBlockMeta {
643
770
  }
644
771
  }
645
772
  }
773
+
774
+ extension Array where Element == FfiSubtreeRoot {
775
+ func deallocateElements() {
776
+ self.forEach { element in
777
+ element.root_hash_ptr.deallocate()
778
+ }
779
+ }
780
+ }