[#888] Make actor from ZcashRustBackendWelding
Closes #888. - `ZcashRustBackend` is actor now. So majority of methods in this actor are now async. - Some methods stayed `static` in `ZcashRustBackend`. It would be hard to pass instance of the `ZcashRustBackend` to the places where these methods are used in static manner. And it would change lot of APIs. But it isn't problem from technical perspective because these methods would be `nonisolated` otherwise. - Methods `lastError()` and `getLastError()` in `ZcashRustBackend` are now private. This makes sure that ther won't be aby race condition between other methods and these two error methods. - All the methods for which was `lastError()` used in code now throw error. So `lastError()` is no longer needed outside of the `ZcashRustBackend`. - There are in the public API related to `DerivationTool`. - `DerivationTool` now requires instance of the `ZcashRustBackend`. And `ZcashRustBackend` isn't public type. So `DerivationTool` doesn't have any public constructor now. It can be created only via `Initializer.makeDerivationTool()` instance method. - `deriveUnifiedSpendingKey()` and `deriveUnifiedFullViewingKey()` in `DerivationTool` are now async. It is because these are using `ZcashRustBackend` inside. `DerivationTool` offers alternative (closure and combine) APIs. But downside is that there is no sync API to dervie spending key or viewing key. - Some methods of the `DerivationTool` are now static. These methods don't use anything that requires instance of the `DerivationTool` inside. [#888] Use Sourcery to generate mocks - I wrote mock for `Synchronizer` manually. And it's tedious and long and boring work. - Now `ZcashRustBackendWelding` is changed a lot so it means `MockRustBackend` must be changed a lot. So I decided to introduce `sourcery` to generate mocks from protocols so we don't have to do it manually ever. - To generate mocks go to `ZcashLightClientKit/Tests/TestUtils/Sourcery` directory and run `generateMocks.sh` script. - Your protocol must be mentioned in `AutoMockable.swift` file. Generated mocks are in `AutoMockable.generated.swift` file. [#888] Fix Offline tests - Offline tests target now runs and tests are green. - There is log of changes in tests. But logic is not changed. - Updated `AutoMockable.stencil` so sourcery is able to generate mock as actor when protocol is marked with: `// sourcery: mockActor`. - Last few updates in `ZcashRustBackendWelding`. In previous PR `rewindCacheToHeight` methods was overlooked and it didn't throw error. - Removed `MockRustBackend` and using generated `ZCashRustBackendWeldingMock` instead. - Using generated `SynchronizerMock`. [#888] Fix NetworkTests - Changed a bit how rust backend mock is used in the tests. Introduced `RustBackendMockHelper`. There are some state variables that must be preserved within one instance of the mock. This helper does exactly this. It keeps this state variables in the memory and helping mock to work as expected. [#888] Fix Darkside tests Create ZcashKeyDeriving internal protocol Use New DerivationTool that does not require RustBackend Remove duplicated methods that had been copied over [#888] Fix potentially broken tests I broke the tests because I moved `testTempDirectory` from each `TestCase` to the `Environment`. By this I caused that each tests uses exactly same URL. Which is directly against purpose of `testTempDirectory`. So now each test calls this one and store it to local variable. So each test has unique URL. [#888] Add ability to mock nonisolated methods to AutoMockable.stencil [#888] Add changelog and fix the documentation in ZcashRustBackendWelding [#888] Rename derivation rust backend protocol and remove static methods - Renamed `ZcashKeyDeriving` to `ZcashKeyDerivationBackendWelding`. So the naming scheme is same as for `ZcashRustBackendWelding`. - `ZcashKeyDerivationBackend` is now struct instead of enum. - Methods in `ZcashKeyDerivationBackendWelding` (except one) are no longer static. Because of this the respective methods in `DerivationTool` aren't also static anymore.
This commit is contained in:
parent
6b7fbdd908
commit
2bbc5800bd
|
@ -76,7 +76,6 @@ Pods
|
||||||
# do not commit generated libraries to this repo
|
# do not commit generated libraries to this repo
|
||||||
lib
|
lib
|
||||||
*.a
|
*.a
|
||||||
*.generated.swift
|
|
||||||
env-vars.sh
|
env-vars.sh
|
||||||
|
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
|
@ -15,6 +15,7 @@ excluded:
|
||||||
- ZcashLightClientKitTests/Constants.generated.swift
|
- ZcashLightClientKitTests/Constants.generated.swift
|
||||||
- build/
|
- build/
|
||||||
- docs/
|
- docs/
|
||||||
|
- Tests/TestUtils/Sourcery/GeneratedMocks/AutoMockable.generated.swift
|
||||||
|
|
||||||
disabled_rules:
|
disabled_rules:
|
||||||
- notification_center_detachment
|
- notification_center_detachment
|
||||||
|
|
|
@ -11,6 +11,7 @@ excluded:
|
||||||
- ZcashLightClientKitTests/Constants.generated.swift
|
- ZcashLightClientKitTests/Constants.generated.swift
|
||||||
- build/
|
- build/
|
||||||
- docs/
|
- docs/
|
||||||
|
- Tests/TestUtils/Sourcery/GeneratedMocks/AutoMockable.generated.swift
|
||||||
|
|
||||||
disabled_rules:
|
disabled_rules:
|
||||||
- notification_center_detachment
|
- notification_center_detachment
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
# unreleased
|
# unreleased
|
||||||
|
### [#888] Updates to layer between Swift and Rust
|
||||||
|
|
||||||
|
This is mostly internal change. But it also touches the public API.
|
||||||
|
|
||||||
|
`KeyDeriving` protocol is changed. And therefore `DerivationTool` is changed. `deriveUnifiedSpendingKey(seed:accountIndex:)` and
|
||||||
|
`deriveUnifiedFullViewingKey(from:)` methods are now async. `DerivationTool` offers alternatives for these methods. Alternatives are using either
|
||||||
|
closures or Combine.
|
||||||
|
|
||||||
### [#469] ZcashRustBackendWelding to Async
|
### [#469] ZcashRustBackendWelding to Async
|
||||||
|
|
||||||
This is mostly internal change. But it also touches the public API.
|
This is mostly internal change. But it also touches the public API.
|
||||||
|
|
|
@ -104,6 +104,20 @@
|
||||||
ReferencedContainer = "container:../..">
|
ReferencedContainer = "container:../..">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildActionEntry>
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "0DA1C4A627D11B2900E5006E"
|
||||||
|
BuildableName = "ZcashLightClientSampleTests.xctest"
|
||||||
|
BlueprintName = "ZcashLightClientSampleTests"
|
||||||
|
ReferencedContainer = "container:ZcashLightClientSample.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
</BuildActionEntries>
|
</BuildActionEntries>
|
||||||
</BuildAction>
|
</BuildAction>
|
||||||
<TestAction
|
<TestAction
|
||||||
|
|
|
@ -32,9 +32,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
var sharedViewingKey: UnifiedFullViewingKey {
|
var sharedViewingKey: UnifiedFullViewingKey {
|
||||||
return try! DerivationTool(networkType: kZcashNetwork.networkType)
|
get async {
|
||||||
.deriveUnifiedSpendingKey(seed: DemoAppConfig.defaultSeed, accountIndex: 0)
|
let derivationTool = sharedWallet.makeDerivationTool()
|
||||||
.deriveFullViewingKey()
|
let spendingKey = try! await derivationTool
|
||||||
|
.deriveUnifiedSpendingKey(seed: DemoAppConfig.defaultSeed, accountIndex: 0)
|
||||||
|
|
||||||
|
return try! await derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var sharedWallet: Initializer {
|
var sharedWallet: Initializer {
|
||||||
|
|
|
@ -39,24 +39,26 @@ class GetUTXOsViewController: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func shieldFunds(_ sender: Any) {
|
@IBAction func shieldFunds(_ sender: Any) {
|
||||||
do {
|
Task { @MainActor in
|
||||||
let derivationTool = DerivationTool(networkType: kZcashNetwork.networkType)
|
do {
|
||||||
|
let derivationTool = AppDelegate.shared.sharedWallet.makeDerivationTool()
|
||||||
|
|
||||||
let usk = try derivationTool.deriveUnifiedSpendingKey(seed: DemoAppConfig.defaultSeed, accountIndex: 0)
|
let usk = try await derivationTool.deriveUnifiedSpendingKey(seed: DemoAppConfig.defaultSeed, accountIndex: 0)
|
||||||
|
|
||||||
KRProgressHUD.showMessage("🛡 Shielding 🛡")
|
KRProgressHUD.showMessage("🛡 Shielding 🛡")
|
||||||
|
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
let transaction = try await AppDelegate.shared.sharedSynchronizer.shieldFunds(
|
let transaction = try await AppDelegate.shared.sharedSynchronizer.shieldFunds(
|
||||||
spendingKey: usk,
|
spendingKey: usk,
|
||||||
memo: try Memo(string: "shielding is fun!"),
|
memo: try Memo(string: "shielding is fun!"),
|
||||||
shieldingThreshold: Zatoshi(10000)
|
shieldingThreshold: Zatoshi(10000)
|
||||||
)
|
)
|
||||||
KRProgressHUD.dismiss()
|
KRProgressHUD.dismiss()
|
||||||
self.messageLabel.text = "funds shielded \(transaction)"
|
self.messageLabel.text = "funds shielded \(transaction)"
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
self.messageLabel.text = "Shielding failed \(error)"
|
||||||
}
|
}
|
||||||
} catch {
|
|
||||||
self.messageLabel.text = "Shielding failed \(error)"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,13 +42,15 @@ class SendViewController: UIViewController {
|
||||||
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(viewTapped(_:)))
|
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(viewTapped(_:)))
|
||||||
self.view.addGestureRecognizer(tapRecognizer)
|
self.view.addGestureRecognizer(tapRecognizer)
|
||||||
setUp()
|
setUp()
|
||||||
|
|
||||||
closureSynchronizer.prepare(
|
Task { @MainActor in
|
||||||
with: DemoAppConfig.defaultSeed,
|
closureSynchronizer.prepare(
|
||||||
viewingKeys: [AppDelegate.shared.sharedViewingKey],
|
with: DemoAppConfig.defaultSeed,
|
||||||
walletBirthday: DemoAppConfig.defaultBirthdayHeight
|
viewingKeys: [await AppDelegate.shared.sharedViewingKey],
|
||||||
) { result in
|
walletBirthday: DemoAppConfig.defaultBirthdayHeight
|
||||||
loggerProxy.debug("Prepare result: \(result)")
|
) { result in
|
||||||
|
loggerProxy.debug("Prepare result: \(result)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,14 +218,8 @@ class SendViewController: UIViewController {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let spendingKey = try? DerivationTool(
|
let derivationTool = AppDelegate.shared.sharedWallet.makeDerivationTool()
|
||||||
networkType: kZcashNetwork.networkType
|
guard let spendingKey = try? await derivationTool.deriveUnifiedSpendingKey(seed: DemoAppConfig.defaultSeed, accountIndex: 0) else {
|
||||||
)
|
|
||||||
.deriveUnifiedSpendingKey(
|
|
||||||
seed: DemoAppConfig.defaultSeed,
|
|
||||||
accountIndex: 0
|
|
||||||
)
|
|
||||||
else {
|
|
||||||
loggerProxy.error("NO SPENDING KEY")
|
loggerProxy.error("NO SPENDING KEY")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,33 +58,35 @@ class SyncBlocksListViewController: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func didTapOnButton(index: Int) async {
|
private func didTapOnButton(index: Int) async {
|
||||||
let synchronizerData = synchronizerData[index]
|
Task { @MainActor in
|
||||||
let synchronizer = synchronizers[index]
|
let synchronizerData = synchronizerData[index]
|
||||||
let syncStatus = synchronizer.latestState.syncStatus
|
let synchronizer = synchronizers[index]
|
||||||
|
let syncStatus = synchronizer.latestState.syncStatus
|
||||||
|
|
||||||
loggerProxy.debug("Processing synchronizer with alias \(synchronizer.alias.description) \(index)")
|
loggerProxy.debug("Processing synchronizer with alias \(synchronizer.alias.description) \(index)")
|
||||||
|
|
||||||
switch syncStatus {
|
switch syncStatus {
|
||||||
case .stopped, .unprepared, .synced, .disconnected, .error:
|
case .stopped, .unprepared, .synced, .disconnected, .error:
|
||||||
do {
|
do {
|
||||||
if syncStatus == .unprepared {
|
if syncStatus == .unprepared {
|
||||||
let viewingKey = try! DerivationTool(networkType: kZcashNetwork.networkType)
|
let derivationTool = AppDelegate.shared.sharedWallet.makeDerivationTool()
|
||||||
.deriveUnifiedSpendingKey(seed: synchronizerData.seed, accountIndex: 0)
|
let spendingKey = try await derivationTool.deriveUnifiedSpendingKey(seed: synchronizerData.seed, accountIndex: 0)
|
||||||
.deriveFullViewingKey()
|
let viewingKey = try await derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
|
|
||||||
_ = try! await synchronizer.prepare(
|
_ = try! await synchronizer.prepare(
|
||||||
with: synchronizerData.seed,
|
with: synchronizerData.seed,
|
||||||
viewingKeys: [viewingKey],
|
viewingKeys: [viewingKey],
|
||||||
walletBirthday: synchronizerData.birthday
|
walletBirthday: synchronizerData.birthday
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
try await synchronizer.start(retry: false)
|
||||||
|
} catch {
|
||||||
|
loggerProxy.error("Can't start synchronizer: \(error)")
|
||||||
}
|
}
|
||||||
|
case .syncing, .enhancing, .fetching:
|
||||||
try await synchronizer.start(retry: false)
|
await synchronizer.stop()
|
||||||
} catch {
|
|
||||||
loggerProxy.error("Can't start synchronizer: \(error)")
|
|
||||||
}
|
}
|
||||||
case .syncing, .enhancing, .fetching:
|
|
||||||
await synchronizer.stop()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,9 @@ let package = Package(
|
||||||
dependencies: ["ZcashLightClientKit"],
|
dependencies: ["ZcashLightClientKit"],
|
||||||
path: "Tests/TestUtils",
|
path: "Tests/TestUtils",
|
||||||
exclude: [
|
exclude: [
|
||||||
"proto/darkside.proto"
|
"proto/darkside.proto",
|
||||||
|
"Sourcery/AutoMockable.stencil",
|
||||||
|
"Sourcery/generateMocks"
|
||||||
],
|
],
|
||||||
resources: [
|
resources: [
|
||||||
.copy("Resources/test_data.db"),
|
.copy("Resources/test_data.db"),
|
||||||
|
|
|
@ -316,7 +316,7 @@ actor CompactBlockProcessor {
|
||||||
var storage: CompactBlockRepository
|
var storage: CompactBlockRepository
|
||||||
var transactionRepository: TransactionRepository
|
var transactionRepository: TransactionRepository
|
||||||
var accountRepository: AccountRepository
|
var accountRepository: AccountRepository
|
||||||
var rustBackend: ZcashRustBackendWelding.Type
|
var rustBackend: ZcashRustBackendWelding
|
||||||
private var retryAttempts: Int = 0
|
private var retryAttempts: Int = 0
|
||||||
private var backoffTimer: Timer?
|
private var backoffTimer: Timer?
|
||||||
private var lastChainValidationFailure: BlockHeight?
|
private var lastChainValidationFailure: BlockHeight?
|
||||||
|
@ -344,7 +344,7 @@ actor CompactBlockProcessor {
|
||||||
init(
|
init(
|
||||||
service: LightWalletService,
|
service: LightWalletService,
|
||||||
storage: CompactBlockRepository,
|
storage: CompactBlockRepository,
|
||||||
backend: ZcashRustBackendWelding.Type,
|
rustBackend: ZcashRustBackendWelding,
|
||||||
config: Configuration,
|
config: Configuration,
|
||||||
metrics: SDKMetrics,
|
metrics: SDKMetrics,
|
||||||
logger: Logger
|
logger: Logger
|
||||||
|
@ -352,11 +352,9 @@ actor CompactBlockProcessor {
|
||||||
self.init(
|
self.init(
|
||||||
service: service,
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
backend: backend,
|
rustBackend: rustBackend,
|
||||||
config: config,
|
config: config,
|
||||||
repository: TransactionRepositoryBuilder.build(
|
repository: TransactionRepositoryBuilder.build(dataDbURL: config.dataDb),
|
||||||
dataDbURL: config.dataDb
|
|
||||||
),
|
|
||||||
accountRepository: AccountRepositoryBuilder.build(dataDbURL: config.dataDb, readOnly: true, logger: logger),
|
accountRepository: AccountRepositoryBuilder.build(dataDbURL: config.dataDb, readOnly: true, logger: logger),
|
||||||
metrics: metrics,
|
metrics: metrics,
|
||||||
logger: logger
|
logger: logger
|
||||||
|
@ -375,7 +373,7 @@ actor CompactBlockProcessor {
|
||||||
self.init(
|
self.init(
|
||||||
service: initializer.lightWalletService,
|
service: initializer.lightWalletService,
|
||||||
storage: initializer.storage,
|
storage: initializer.storage,
|
||||||
backend: initializer.rustBackend,
|
rustBackend: initializer.rustBackend,
|
||||||
config: Configuration(
|
config: Configuration(
|
||||||
alias: initializer.alias,
|
alias: initializer.alias,
|
||||||
fsBlockCacheRoot: initializer.fsBlockDbRoot,
|
fsBlockCacheRoot: initializer.fsBlockDbRoot,
|
||||||
|
@ -396,7 +394,7 @@ actor CompactBlockProcessor {
|
||||||
internal init(
|
internal init(
|
||||||
service: LightWalletService,
|
service: LightWalletService,
|
||||||
storage: CompactBlockRepository,
|
storage: CompactBlockRepository,
|
||||||
backend: ZcashRustBackendWelding.Type,
|
rustBackend: ZcashRustBackendWelding,
|
||||||
config: Configuration,
|
config: Configuration,
|
||||||
repository: TransactionRepository,
|
repository: TransactionRepository,
|
||||||
accountRepository: AccountRepository,
|
accountRepository: AccountRepository,
|
||||||
|
@ -420,73 +418,57 @@ actor CompactBlockProcessor {
|
||||||
self.blockDownloaderService = blockDownloaderService
|
self.blockDownloaderService = blockDownloaderService
|
||||||
self.blockDownloader = blockDownloader
|
self.blockDownloader = blockDownloader
|
||||||
|
|
||||||
let blockValidatorConfig = BlockValidatorConfig(
|
|
||||||
fsBlockCacheRoot: config.fsBlockCacheRoot,
|
|
||||||
dataDB: config.dataDb,
|
|
||||||
networkType: config.network.networkType
|
|
||||||
)
|
|
||||||
self.blockValidator = BlockValidatorImpl(
|
self.blockValidator = BlockValidatorImpl(
|
||||||
config: blockValidatorConfig,
|
rustBackend: rustBackend,
|
||||||
rustBackend: backend,
|
|
||||||
metrics: metrics,
|
metrics: metrics,
|
||||||
logger: logger
|
logger: logger
|
||||||
)
|
)
|
||||||
|
|
||||||
let blockScannerConfig = BlockScannerConfig(
|
let blockScannerConfig = BlockScannerConfig(
|
||||||
fsBlockCacheRoot: config.fsBlockCacheRoot,
|
|
||||||
dataDB: config.dataDb,
|
|
||||||
networkType: config.network.networkType,
|
networkType: config.network.networkType,
|
||||||
scanningBatchSize: config.scanningBatchSize
|
scanningBatchSize: config.scanningBatchSize
|
||||||
)
|
)
|
||||||
self.blockScanner = BlockScannerImpl(
|
self.blockScanner = BlockScannerImpl(
|
||||||
config: blockScannerConfig,
|
config: blockScannerConfig,
|
||||||
rustBackend: backend,
|
rustBackend: rustBackend,
|
||||||
transactionRepository: repository,
|
transactionRepository: repository,
|
||||||
metrics: metrics,
|
metrics: metrics,
|
||||||
logger: logger
|
logger: logger
|
||||||
)
|
)
|
||||||
|
|
||||||
let blockEnhancerConfig = BlockEnhancerConfig(dataDb: config.dataDb, networkType: config.network.networkType)
|
|
||||||
self.blockEnhancer = BlockEnhancerImpl(
|
self.blockEnhancer = BlockEnhancerImpl(
|
||||||
blockDownloaderService: blockDownloaderService,
|
blockDownloaderService: blockDownloaderService,
|
||||||
config: blockEnhancerConfig,
|
|
||||||
internalSyncProgress: internalSyncProgress,
|
internalSyncProgress: internalSyncProgress,
|
||||||
rustBackend: backend,
|
rustBackend: rustBackend,
|
||||||
transactionRepository: repository,
|
transactionRepository: repository,
|
||||||
metrics: metrics,
|
metrics: metrics,
|
||||||
logger: logger
|
logger: logger
|
||||||
)
|
)
|
||||||
|
|
||||||
let utxoFetcherConfig = UTXOFetcherConfig(
|
let utxoFetcherConfig = UTXOFetcherConfig(walletBirthdayProvider: config.walletBirthdayProvider)
|
||||||
dataDb: config.dataDb,
|
|
||||||
networkType: config.network.networkType,
|
|
||||||
walletBirthdayProvider: config.walletBirthdayProvider
|
|
||||||
)
|
|
||||||
self.utxoFetcher = UTXOFetcherImpl(
|
self.utxoFetcher = UTXOFetcherImpl(
|
||||||
accountRepository: accountRepository,
|
accountRepository: accountRepository,
|
||||||
blockDownloaderService: blockDownloaderService,
|
blockDownloaderService: blockDownloaderService,
|
||||||
config: utxoFetcherConfig,
|
config: utxoFetcherConfig,
|
||||||
internalSyncProgress: internalSyncProgress,
|
internalSyncProgress: internalSyncProgress,
|
||||||
rustBackend: backend,
|
rustBackend: rustBackend,
|
||||||
metrics: metrics,
|
metrics: metrics,
|
||||||
logger: logger
|
logger: logger
|
||||||
)
|
)
|
||||||
|
|
||||||
let saplingParametersHandlerConfig = SaplingParametersHandlerConfig(
|
let saplingParametersHandlerConfig = SaplingParametersHandlerConfig(
|
||||||
dataDb: config.dataDb,
|
|
||||||
networkType: config.network.networkType,
|
|
||||||
outputParamsURL: config.outputParamsURL,
|
outputParamsURL: config.outputParamsURL,
|
||||||
spendParamsURL: config.spendParamsURL,
|
spendParamsURL: config.spendParamsURL,
|
||||||
saplingParamsSourceURL: config.saplingParamsSourceURL
|
saplingParamsSourceURL: config.saplingParamsSourceURL
|
||||||
)
|
)
|
||||||
self.saplingParametersHandler = SaplingParametersHandlerImpl(
|
self.saplingParametersHandler = SaplingParametersHandlerImpl(
|
||||||
config: saplingParametersHandlerConfig,
|
config: saplingParametersHandlerConfig,
|
||||||
rustBackend: backend,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
)
|
)
|
||||||
|
|
||||||
self.service = service
|
self.service = service
|
||||||
self.rustBackend = backend
|
self.rustBackend = rustBackend
|
||||||
self.storage = storage
|
self.storage = storage
|
||||||
self.config = config
|
self.config = config
|
||||||
self.transactionRepository = repository
|
self.transactionRepository = repository
|
||||||
|
@ -517,8 +499,8 @@ actor CompactBlockProcessor {
|
||||||
_ info: LightWalletdInfo,
|
_ info: LightWalletdInfo,
|
||||||
saplingActivation: BlockHeight,
|
saplingActivation: BlockHeight,
|
||||||
localNetwork: ZcashNetwork,
|
localNetwork: ZcashNetwork,
|
||||||
rustBackend: ZcashRustBackendWelding.Type
|
rustBackend: ZcashRustBackendWelding
|
||||||
) throws {
|
) async throws {
|
||||||
// check network types
|
// check network types
|
||||||
guard let remoteNetworkType = NetworkType.forChainName(info.chainName) else {
|
guard let remoteNetworkType = NetworkType.forChainName(info.chainName) else {
|
||||||
throw CompactBlockProcessorError.generalError(
|
throw CompactBlockProcessorError.generalError(
|
||||||
|
@ -536,7 +518,7 @@ actor CompactBlockProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check branch id
|
// check branch id
|
||||||
let localBranch = try rustBackend.consensusBranchIdFor(height: Int32(info.blockHeight), networkType: localNetwork.networkType)
|
let localBranch = try rustBackend.consensusBranchIdFor(height: Int32(info.blockHeight))
|
||||||
|
|
||||||
guard let remoteBranchID = ConsensusBranchID.fromString(info.consensusBranchID) else {
|
guard let remoteBranchID = ConsensusBranchID.fromString(info.consensusBranchID) else {
|
||||||
throw CompactBlockProcessorError.generalError(message: "Consensus BranchIDs don't match this is probably an API or programming error")
|
throw CompactBlockProcessorError.generalError(message: "Consensus BranchIDs don't match this is probably an API or programming error")
|
||||||
|
@ -631,24 +613,21 @@ actor CompactBlockProcessor {
|
||||||
logger.debug("Executing rewind.")
|
logger.debug("Executing rewind.")
|
||||||
let lastDownloaded = await internalSyncProgress.latestDownloadedBlockHeight
|
let lastDownloaded = await internalSyncProgress.latestDownloadedBlockHeight
|
||||||
let height = Int32(context.height ?? lastDownloaded)
|
let height = Int32(context.height ?? lastDownloaded)
|
||||||
let nearestHeight = await rustBackend.getNearestRewindHeight(
|
|
||||||
dbData: config.dataDb,
|
|
||||||
height: height,
|
|
||||||
networkType: self.config.network.networkType
|
|
||||||
)
|
|
||||||
|
|
||||||
guard nearestHeight > 0 else {
|
let nearestHeight: Int32
|
||||||
let error = rustBackend.lastError() ?? RustWeldingError.genericError(
|
do {
|
||||||
message: "unknown error getting nearest rewind height for height: \(height)"
|
nearestHeight = try await rustBackend.getNearestRewindHeight(height: height)
|
||||||
)
|
} catch {
|
||||||
await fail(error)
|
await fail(error)
|
||||||
return await context.completion(.failure(error))
|
return await context.completion(.failure(error))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: [#719] this should be done on the rust layer, https://github.com/zcash/ZcashLightClientKit/issues/719
|
// FIXME: [#719] this should be done on the rust layer, https://github.com/zcash/ZcashLightClientKit/issues/719
|
||||||
let rewindHeight = max(Int32(nearestHeight - 1), Int32(config.walletBirthday))
|
let rewindHeight = max(Int32(nearestHeight - 1), Int32(config.walletBirthday))
|
||||||
guard await rustBackend.rewindToHeight(dbData: config.dataDb, height: rewindHeight, networkType: self.config.network.networkType) else {
|
|
||||||
let error = rustBackend.lastError() ?? RustWeldingError.genericError(message: "unknown error rewinding to height \(height)")
|
do {
|
||||||
|
try await rustBackend.rewindToHeight(height: rewindHeight)
|
||||||
|
} catch {
|
||||||
await fail(error)
|
await fail(error)
|
||||||
return await context.completion(.failure(error))
|
return await context.completion(.failure(error))
|
||||||
}
|
}
|
||||||
|
@ -715,7 +694,7 @@ actor CompactBlockProcessor {
|
||||||
func validateServer() async {
|
func validateServer() async {
|
||||||
do {
|
do {
|
||||||
let info = try await self.service.getInfo()
|
let info = try await self.service.getInfo()
|
||||||
try Self.validateServerInfo(
|
try await Self.validateServerInfo(
|
||||||
info,
|
info,
|
||||||
saplingActivation: self.config.saplingActivation,
|
saplingActivation: self.config.saplingActivation,
|
||||||
localNetwork: self.config.network,
|
localNetwork: self.config.network,
|
||||||
|
@ -1055,14 +1034,10 @@ actor CompactBlockProcessor {
|
||||||
|
|
||||||
self.consecutiveChainValidationErrors += 1
|
self.consecutiveChainValidationErrors += 1
|
||||||
|
|
||||||
let rewindResult = await rustBackend.rewindToHeight(
|
do {
|
||||||
dbData: config.dataDb,
|
try await rustBackend.rewindToHeight(height: Int32(rewindHeight))
|
||||||
height: Int32(rewindHeight),
|
} catch {
|
||||||
networkType: self.config.network.networkType
|
await fail(error)
|
||||||
)
|
|
||||||
|
|
||||||
guard rewindResult else {
|
|
||||||
await fail(rustBackend.lastError() ?? RustWeldingError.genericError(message: "unknown error rewinding to height \(height)"))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1205,11 +1180,7 @@ extension CompactBlockProcessor.State: Equatable {
|
||||||
|
|
||||||
extension CompactBlockProcessor {
|
extension CompactBlockProcessor {
|
||||||
func getUnifiedAddress(accountIndex: Int) async throws -> UnifiedAddress {
|
func getUnifiedAddress(accountIndex: Int) async throws -> UnifiedAddress {
|
||||||
try await rustBackend.getCurrentAddress(
|
try await rustBackend.getCurrentAddress(account: Int32(accountIndex))
|
||||||
dbData: config.dataDb,
|
|
||||||
account: Int32(accountIndex),
|
|
||||||
networkType: config.network.networkType
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSaplingAddress(accountIndex: Int) async throws -> SaplingAddress {
|
func getSaplingAddress(accountIndex: Int) async throws -> SaplingAddress {
|
||||||
|
@ -1227,18 +1198,10 @@ extension CompactBlockProcessor {
|
||||||
|
|
||||||
return WalletBalance(
|
return WalletBalance(
|
||||||
verified: Zatoshi(
|
verified: Zatoshi(
|
||||||
try await rustBackend.getVerifiedTransparentBalance(
|
try await rustBackend.getVerifiedTransparentBalance(account: Int32(accountIndex))
|
||||||
dbData: config.dataDb,
|
|
||||||
account: Int32(accountIndex),
|
|
||||||
networkType: config.network.networkType
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
total: Zatoshi(
|
total: Zatoshi(
|
||||||
try await rustBackend.getTransparentBalance(
|
try await rustBackend.getTransparentBalance(account: Int32(accountIndex))
|
||||||
dbData: config.dataDb,
|
|
||||||
account: Int32(accountIndex),
|
|
||||||
networkType: config.network.networkType
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1269,19 +1232,15 @@ extension CompactBlockProcessor {
|
||||||
var skipped: [UnspentTransactionOutputEntity] = []
|
var skipped: [UnspentTransactionOutputEntity] = []
|
||||||
for utxo in utxos {
|
for utxo in utxos {
|
||||||
do {
|
do {
|
||||||
if try await rustBackend.putUnspentTransparentOutput(
|
try await rustBackend.putUnspentTransparentOutput(
|
||||||
dbData: dataDb,
|
|
||||||
txid: utxo.txid.bytes,
|
txid: utxo.txid.bytes,
|
||||||
index: utxo.index,
|
index: utxo.index,
|
||||||
script: utxo.script.bytes,
|
script: utxo.script.bytes,
|
||||||
value: Int64(utxo.valueZat),
|
value: Int64(utxo.valueZat),
|
||||||
height: utxo.height,
|
height: utxo.height
|
||||||
networkType: self.config.network.networkType
|
)
|
||||||
) {
|
|
||||||
refreshed.append(utxo)
|
refreshed.append(utxo)
|
||||||
} else {
|
|
||||||
skipped.append(utxo)
|
|
||||||
}
|
|
||||||
} catch {
|
} catch {
|
||||||
logger.info("failed to put utxo - error: \(error)")
|
logger.info("failed to put utxo - error: \(error)")
|
||||||
skipped.append(utxo)
|
skipped.append(utxo)
|
||||||
|
@ -1389,7 +1348,7 @@ extension CompactBlockProcessor {
|
||||||
downloaderService: BlockDownloaderService,
|
downloaderService: BlockDownloaderService,
|
||||||
transactionRepository: TransactionRepository,
|
transactionRepository: TransactionRepository,
|
||||||
config: Configuration,
|
config: Configuration,
|
||||||
rustBackend: ZcashRustBackendWelding.Type,
|
rustBackend: ZcashRustBackendWelding,
|
||||||
internalSyncProgress: InternalSyncProgress
|
internalSyncProgress: InternalSyncProgress
|
||||||
) async throws -> CompactBlockProcessor.NextState {
|
) async throws -> CompactBlockProcessor.NextState {
|
||||||
// It should be ok to not create new Task here because this method is already async. But for some reason something not good happens
|
// It should be ok to not create new Task here because this method is already async. But for some reason something not good happens
|
||||||
|
@ -1397,7 +1356,7 @@ extension CompactBlockProcessor {
|
||||||
let task = Task(priority: .userInitiated) {
|
let task = Task(priority: .userInitiated) {
|
||||||
let info = try await service.getInfo()
|
let info = try await service.getInfo()
|
||||||
|
|
||||||
try CompactBlockProcessor.validateServerInfo(
|
try await CompactBlockProcessor.validateServerInfo(
|
||||||
info,
|
info,
|
||||||
saplingActivation: config.saplingActivation,
|
saplingActivation: config.saplingActivation,
|
||||||
localNetwork: config.network,
|
localNetwork: config.network,
|
||||||
|
|
|
@ -14,20 +14,14 @@ enum BlockEnhancerError: Error {
|
||||||
case txIdNotFound(txId: Data)
|
case txIdNotFound(txId: Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BlockEnhancerConfig {
|
|
||||||
let dataDb: URL
|
|
||||||
let networkType: NetworkType
|
|
||||||
}
|
|
||||||
|
|
||||||
protocol BlockEnhancer {
|
protocol BlockEnhancer {
|
||||||
func enhance(at range: CompactBlockRange, didEnhance: (EnhancementProgress) async -> Void) async throws -> [ZcashTransaction.Overview]
|
func enhance(at range: CompactBlockRange, didEnhance: (EnhancementProgress) async -> Void) async throws -> [ZcashTransaction.Overview]
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BlockEnhancerImpl {
|
struct BlockEnhancerImpl {
|
||||||
let blockDownloaderService: BlockDownloaderService
|
let blockDownloaderService: BlockDownloaderService
|
||||||
let config: BlockEnhancerConfig
|
|
||||||
let internalSyncProgress: InternalSyncProgress
|
let internalSyncProgress: InternalSyncProgress
|
||||||
let rustBackend: ZcashRustBackendWelding.Type
|
let rustBackend: ZcashRustBackendWelding
|
||||||
let transactionRepository: TransactionRepository
|
let transactionRepository: TransactionRepository
|
||||||
let metrics: SDKMetrics
|
let metrics: SDKMetrics
|
||||||
let logger: Logger
|
let logger: Logger
|
||||||
|
@ -41,17 +35,13 @@ struct BlockEnhancerImpl {
|
||||||
let block = String(describing: transaction.minedHeight)
|
let block = String(describing: transaction.minedHeight)
|
||||||
logger.debug("Decrypting and storing transaction id: \(transactionID) block: \(block)")
|
logger.debug("Decrypting and storing transaction id: \(transactionID) block: \(block)")
|
||||||
|
|
||||||
let decryptionResult = await rustBackend.decryptAndStoreTransaction(
|
do {
|
||||||
dbData: config.dataDb,
|
try await rustBackend.decryptAndStoreTransaction(
|
||||||
txBytes: fetchedTransaction.raw.bytes,
|
txBytes: fetchedTransaction.raw.bytes,
|
||||||
minedHeight: Int32(fetchedTransaction.minedHeight),
|
minedHeight: Int32(fetchedTransaction.minedHeight)
|
||||||
networkType: config.networkType
|
|
||||||
)
|
|
||||||
|
|
||||||
guard decryptionResult else {
|
|
||||||
throw BlockEnhancerError.decryptError(
|
|
||||||
error: rustBackend.lastError() ?? .genericError(message: "`decryptAndStoreTransaction` failed. No message available")
|
|
||||||
)
|
)
|
||||||
|
} catch {
|
||||||
|
throw BlockEnhancerError.decryptError(error: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
let confirmedTx: ZcashTransaction.Overview
|
let confirmedTx: ZcashTransaction.Overview
|
||||||
|
|
|
@ -13,8 +13,6 @@ enum UTXOFetcherError: Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UTXOFetcherConfig {
|
struct UTXOFetcherConfig {
|
||||||
let dataDb: URL
|
|
||||||
let networkType: NetworkType
|
|
||||||
let walletBirthdayProvider: () async -> BlockHeight
|
let walletBirthdayProvider: () async -> BlockHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +25,7 @@ struct UTXOFetcherImpl {
|
||||||
let blockDownloaderService: BlockDownloaderService
|
let blockDownloaderService: BlockDownloaderService
|
||||||
let config: UTXOFetcherConfig
|
let config: UTXOFetcherConfig
|
||||||
let internalSyncProgress: InternalSyncProgress
|
let internalSyncProgress: InternalSyncProgress
|
||||||
let rustBackend: ZcashRustBackendWelding.Type
|
let rustBackend: ZcashRustBackendWelding
|
||||||
let metrics: SDKMetrics
|
let metrics: SDKMetrics
|
||||||
let logger: Logger
|
let logger: Logger
|
||||||
}
|
}
|
||||||
|
@ -41,11 +39,7 @@ extension UTXOFetcherImpl: UTXOFetcher {
|
||||||
|
|
||||||
var tAddresses: [TransparentAddress] = []
|
var tAddresses: [TransparentAddress] = []
|
||||||
for account in accounts {
|
for account in accounts {
|
||||||
tAddresses += try await rustBackend.listTransparentReceivers(
|
tAddresses += try await rustBackend.listTransparentReceivers(account: Int32(account))
|
||||||
dbData: config.dataDb,
|
|
||||||
account: Int32(account),
|
|
||||||
networkType: config.networkType
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var utxos: [UnspentTransactionOutputEntity] = []
|
var utxos: [UnspentTransactionOutputEntity] = []
|
||||||
|
@ -64,19 +58,15 @@ extension UTXOFetcherImpl: UTXOFetcher {
|
||||||
let startTime = Date()
|
let startTime = Date()
|
||||||
for utxo in utxos {
|
for utxo in utxos {
|
||||||
do {
|
do {
|
||||||
if try await rustBackend.putUnspentTransparentOutput(
|
try await rustBackend.putUnspentTransparentOutput(
|
||||||
dbData: config.dataDb,
|
|
||||||
txid: utxo.txid.bytes,
|
txid: utxo.txid.bytes,
|
||||||
index: utxo.index,
|
index: utxo.index,
|
||||||
script: utxo.script.bytes,
|
script: utxo.script.bytes,
|
||||||
value: Int64(utxo.valueZat),
|
value: Int64(utxo.valueZat),
|
||||||
height: utxo.height,
|
height: utxo.height
|
||||||
networkType: config.networkType
|
)
|
||||||
) {
|
|
||||||
refreshed.append(utxo)
|
refreshed.append(utxo)
|
||||||
} else {
|
|
||||||
skipped.append(utxo)
|
|
||||||
}
|
|
||||||
|
|
||||||
await internalSyncProgress.set(utxo.height, .latestUTXOFetchedHeight)
|
await internalSyncProgress.set(utxo.height, .latestUTXOFetchedHeight)
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
@ -52,7 +52,10 @@ extension FSCompactBlockRepository: CompactBlockRepository {
|
||||||
try fileManager.createDirectory(at: blocksDirectory, withIntermediateDirectories: true)
|
try fileManager.createDirectory(at: blocksDirectory, withIntermediateDirectories: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
guard try await self.metadataStore.initFsBlockDbRoot(self.fsBlockDbRoot) else {
|
do {
|
||||||
|
try await self.metadataStore.initFsBlockDbRoot()
|
||||||
|
} catch {
|
||||||
|
logger.error("Blocks metadata store init failed with error: \(error)")
|
||||||
throw CompactBlockRepositoryError.failedToInitializeCache
|
throw CompactBlockRepositoryError.failedToInitializeCache
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,12 +213,12 @@ extension FSBlockFileWriter {
|
||||||
struct FSMetadataStore {
|
struct FSMetadataStore {
|
||||||
var saveBlocksMeta: ([ZcashCompactBlock]) async throws -> Void
|
var saveBlocksMeta: ([ZcashCompactBlock]) async throws -> Void
|
||||||
var rewindToHeight: (BlockHeight) async throws -> Void
|
var rewindToHeight: (BlockHeight) async throws -> Void
|
||||||
var initFsBlockDbRoot: (URL) async throws -> Bool
|
var initFsBlockDbRoot: () async throws -> Void
|
||||||
var latestHeight: () async -> BlockHeight
|
var latestHeight: () async -> BlockHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FSMetadataStore {
|
extension FSMetadataStore {
|
||||||
static func live(fsBlockDbRoot: URL, rustBackend: ZcashRustBackendWelding.Type, logger: Logger) -> FSMetadataStore {
|
static func live(fsBlockDbRoot: URL, rustBackend: ZcashRustBackendWelding, logger: Logger) -> FSMetadataStore {
|
||||||
FSMetadataStore { blocks in
|
FSMetadataStore { blocks in
|
||||||
try await FSMetadataStore.saveBlocksMeta(
|
try await FSMetadataStore.saveBlocksMeta(
|
||||||
blocks,
|
blocks,
|
||||||
|
@ -224,13 +227,15 @@ extension FSMetadataStore {
|
||||||
logger: logger
|
logger: logger
|
||||||
)
|
)
|
||||||
} rewindToHeight: { height in
|
} rewindToHeight: { height in
|
||||||
guard await rustBackend.rewindCacheToHeight(fsBlockDbRoot: fsBlockDbRoot, height: Int32(height)) else {
|
do {
|
||||||
|
try await rustBackend.rewindCacheToHeight(height: Int32(height))
|
||||||
|
} catch {
|
||||||
throw CompactBlockRepositoryError.failedToRewind(height)
|
throw CompactBlockRepositoryError.failedToRewind(height)
|
||||||
}
|
}
|
||||||
} initFsBlockDbRoot: { dbRootURL in
|
} initFsBlockDbRoot: {
|
||||||
try await rustBackend.initBlockMetadataDb(fsBlockDbRoot: dbRootURL)
|
try await rustBackend.initBlockMetadataDb()
|
||||||
} latestHeight: {
|
} latestHeight: {
|
||||||
await rustBackend.latestCachedBlockHeight(fsBlockDbRoot: fsBlockDbRoot)
|
await rustBackend.latestCachedBlockHeight()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,15 +249,13 @@ extension FSMetadataStore {
|
||||||
static func saveBlocksMeta(
|
static func saveBlocksMeta(
|
||||||
_ blocks: [ZcashCompactBlock],
|
_ blocks: [ZcashCompactBlock],
|
||||||
fsBlockDbRoot: URL,
|
fsBlockDbRoot: URL,
|
||||||
rustBackend: ZcashRustBackendWelding.Type,
|
rustBackend: ZcashRustBackendWelding,
|
||||||
logger: Logger
|
logger: Logger
|
||||||
) async throws {
|
) async throws {
|
||||||
guard !blocks.isEmpty else { return }
|
guard !blocks.isEmpty else { return }
|
||||||
|
|
||||||
do {
|
do {
|
||||||
guard try await rustBackend.writeBlocksMetadata(fsBlockDbRoot: fsBlockDbRoot, blocks: blocks) else {
|
try await rustBackend.writeBlocksMetadata(blocks: blocks)
|
||||||
throw CompactBlockRepositoryError.failedToWriteMetadata
|
|
||||||
}
|
|
||||||
} catch {
|
} catch {
|
||||||
logger.error("Failed to write metadata with error: \(error)")
|
logger.error("Failed to write metadata with error: \(error)")
|
||||||
throw CompactBlockRepositoryError.failedToWriteMetadata
|
throw CompactBlockRepositoryError.failedToWriteMetadata
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct SaplingParametersHandlerConfig {
|
struct SaplingParametersHandlerConfig {
|
||||||
let dataDb: URL
|
|
||||||
let networkType: NetworkType
|
|
||||||
let outputParamsURL: URL
|
let outputParamsURL: URL
|
||||||
let spendParamsURL: URL
|
let spendParamsURL: URL
|
||||||
let saplingParamsSourceURL: SaplingParamsSourceURL
|
let saplingParamsSourceURL: SaplingParamsSourceURL
|
||||||
|
@ -21,7 +19,7 @@ protocol SaplingParametersHandler {
|
||||||
|
|
||||||
struct SaplingParametersHandlerImpl {
|
struct SaplingParametersHandlerImpl {
|
||||||
let config: SaplingParametersHandlerConfig
|
let config: SaplingParametersHandlerConfig
|
||||||
let rustBackend: ZcashRustBackendWelding.Type
|
let rustBackend: ZcashRustBackendWelding
|
||||||
let logger: Logger
|
let logger: Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,16 +28,8 @@ extension SaplingParametersHandlerImpl: SaplingParametersHandler {
|
||||||
try Task.checkCancellation()
|
try Task.checkCancellation()
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let totalShieldedBalance = try await rustBackend.getBalance(
|
let totalShieldedBalance = try await rustBackend.getBalance(account: Int32(0))
|
||||||
dbData: config.dataDb,
|
let totalTransparentBalance = try await rustBackend.getTransparentBalance(account: Int32(0))
|
||||||
account: Int32(0),
|
|
||||||
networkType: config.networkType
|
|
||||||
)
|
|
||||||
let totalTransparentBalance = try await rustBackend.getTransparentBalance(
|
|
||||||
dbData: config.dataDb,
|
|
||||||
account: Int32(0),
|
|
||||||
networkType: config.networkType
|
|
||||||
)
|
|
||||||
|
|
||||||
// Download Sapling parameters only if sapling funds are detected.
|
// Download Sapling parameters only if sapling funds are detected.
|
||||||
guard totalShieldedBalance > 0 || totalTransparentBalance > 0 else { return }
|
guard totalShieldedBalance > 0 || totalTransparentBalance > 0 else { return }
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct BlockScannerConfig {
|
struct BlockScannerConfig {
|
||||||
let fsBlockCacheRoot: URL
|
|
||||||
let dataDB: URL
|
|
||||||
let networkType: NetworkType
|
let networkType: NetworkType
|
||||||
let scanningBatchSize: Int
|
let scanningBatchSize: Int
|
||||||
}
|
}
|
||||||
|
@ -20,7 +18,7 @@ protocol BlockScanner {
|
||||||
|
|
||||||
struct BlockScannerImpl {
|
struct BlockScannerImpl {
|
||||||
let config: BlockScannerConfig
|
let config: BlockScannerConfig
|
||||||
let rustBackend: ZcashRustBackendWelding.Type
|
let rustBackend: ZcashRustBackendWelding
|
||||||
let transactionRepository: TransactionRepository
|
let transactionRepository: TransactionRepository
|
||||||
let metrics: SDKMetrics
|
let metrics: SDKMetrics
|
||||||
let logger: Logger
|
let logger: Logger
|
||||||
|
@ -42,19 +40,16 @@ extension BlockScannerImpl: BlockScanner {
|
||||||
let previousScannedHeight = lastScannedHeight
|
let previousScannedHeight = lastScannedHeight
|
||||||
|
|
||||||
// TODO: [#576] remove this arbitrary batch size https://github.com/zcash/ZcashLightClientKit/issues/576
|
// TODO: [#576] remove this arbitrary batch size https://github.com/zcash/ZcashLightClientKit/issues/576
|
||||||
let batchSize = scanBatchSize(startScanHeight: previousScannedHeight + 1, network: self.config.networkType)
|
let batchSize = scanBatchSize(startScanHeight: previousScannedHeight + 1, network: config.networkType)
|
||||||
|
|
||||||
let scanStartTime = Date()
|
let scanStartTime = Date()
|
||||||
guard await self.rustBackend.scanBlocks(
|
do {
|
||||||
fsBlockDbRoot: config.fsBlockCacheRoot,
|
try await self.rustBackend.scanBlocks(limit: batchSize)
|
||||||
dbData: config.dataDB,
|
} catch {
|
||||||
limit: batchSize,
|
|
||||||
networkType: config.networkType
|
|
||||||
) else {
|
|
||||||
let error: Error = rustBackend.lastError() ?? CompactBlockProcessorError.unknown
|
|
||||||
logger.debug("block scanning failed with error: \(String(describing: error))")
|
logger.debug("block scanning failed with error: \(String(describing: error))")
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
let scanFinishTime = Date()
|
let scanFinishTime = Date()
|
||||||
|
|
||||||
lastScannedHeight = try await transactionRepository.lastScannedHeight()
|
lastScannedHeight = try await transactionRepository.lastScannedHeight()
|
||||||
|
|
|
@ -14,20 +14,13 @@ enum BlockValidatorError: Error {
|
||||||
case failedWithUnknownError
|
case failedWithUnknownError
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BlockValidatorConfig {
|
|
||||||
let fsBlockCacheRoot: URL
|
|
||||||
let dataDB: URL
|
|
||||||
let networkType: NetworkType
|
|
||||||
}
|
|
||||||
|
|
||||||
protocol BlockValidator {
|
protocol BlockValidator {
|
||||||
/// Validate all the downloaded blocks that haven't been yet validated.
|
/// Validate all the downloaded blocks that haven't been yet validated.
|
||||||
func validate() async throws
|
func validate() async throws
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BlockValidatorImpl {
|
struct BlockValidatorImpl {
|
||||||
let config: BlockValidatorConfig
|
let rustBackend: ZcashRustBackendWelding
|
||||||
let rustBackend: ZcashRustBackendWelding.Type
|
|
||||||
let metrics: SDKMetrics
|
let metrics: SDKMetrics
|
||||||
let logger: Logger
|
let logger: Logger
|
||||||
}
|
}
|
||||||
|
@ -37,14 +30,24 @@ extension BlockValidatorImpl: BlockValidator {
|
||||||
try Task.checkCancellation()
|
try Task.checkCancellation()
|
||||||
|
|
||||||
let startTime = Date()
|
let startTime = Date()
|
||||||
let result = await rustBackend.validateCombinedChain(
|
do {
|
||||||
fsBlockDbRoot: config.fsBlockCacheRoot,
|
try await rustBackend.validateCombinedChain(limit: 0)
|
||||||
dbData: config.dataDB,
|
pushProgressReport(startTime: startTime, finishTime: Date())
|
||||||
networkType: config.networkType,
|
logger.debug("validateChainFinished")
|
||||||
limit: 0
|
} catch {
|
||||||
)
|
pushProgressReport(startTime: startTime, finishTime: Date())
|
||||||
let finishTime = Date()
|
|
||||||
|
|
||||||
|
switch error {
|
||||||
|
case let RustWeldingError.invalidChain(upperBound):
|
||||||
|
throw BlockValidatorError.validationFailed(height: BlockHeight(upperBound))
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw BlockValidatorError.failedWithError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func pushProgressReport(startTime: Date, finishTime: Date) {
|
||||||
metrics.pushProgressReport(
|
metrics.pushProgressReport(
|
||||||
progress: BlockProgress(startHeight: 0, targetHeight: 0, progressHeight: 0),
|
progress: BlockProgress(startHeight: 0, targetHeight: 0, progressHeight: 0),
|
||||||
start: startTime,
|
start: startTime,
|
||||||
|
@ -52,24 +55,5 @@ extension BlockValidatorImpl: BlockValidator {
|
||||||
batchSize: 0,
|
batchSize: 0,
|
||||||
operation: .validateBlocks
|
operation: .validateBlocks
|
||||||
)
|
)
|
||||||
|
|
||||||
switch result {
|
|
||||||
case 0:
|
|
||||||
let rustError = rustBackend.lastError()
|
|
||||||
logger.debug("Block validation failed with error: \(String(describing: rustError))")
|
|
||||||
if let rustError {
|
|
||||||
throw BlockValidatorError.failedWithError(rustError)
|
|
||||||
} else {
|
|
||||||
throw BlockValidatorError.failedWithUnknownError
|
|
||||||
}
|
|
||||||
|
|
||||||
case ZcashRustBackendWeldingConstants.validChain:
|
|
||||||
logger.debug("validateChainFinished")
|
|
||||||
return
|
|
||||||
|
|
||||||
default:
|
|
||||||
logger.debug("Block validation failed at height: \(result)")
|
|
||||||
throw BlockValidatorError.validationFailed(height: BlockHeight(result))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,6 @@
|
||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/* These aliases are here to just make the API easier to read. */
|
|
||||||
|
|
||||||
// Publisher which emitts completed or error. No value is emitted.
|
|
||||||
public typealias CompletablePublisher<E: Error> = AnyPublisher<Void, E>
|
|
||||||
// Publisher that either emits one value and then finishes or it emits error.
|
|
||||||
public typealias SinglePublisher = AnyPublisher
|
|
||||||
|
|
||||||
/// This defines a Combine-based API for the SDK. It's expected that the implementation of this protocol is only a very thin layer that translates
|
/// This defines a Combine-based API for the SDK. It's expected that the implementation of this protocol is only a very thin layer that translates
|
||||||
/// async API defined in `Synchronizer` to Combine-based API. And it doesn't do anything else. It's here so each client can choose the API that suits
|
/// async API defined in `Synchronizer` to Combine-based API. And it doesn't do anything else. It's here so each client can choose the API that suits
|
||||||
/// its case the best.
|
/// its case the best.
|
||||||
|
|
|
@ -28,7 +28,7 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
||||||
case rawTransactionId = "txid"
|
case rawTransactionId = "txid"
|
||||||
case fee
|
case fee
|
||||||
}
|
}
|
||||||
|
|
||||||
var recipient: PendingTransactionRecipient
|
var recipient: PendingTransactionRecipient
|
||||||
var accountIndex: Int
|
var accountIndex: Int
|
||||||
var minedHeight: BlockHeight
|
var minedHeight: BlockHeight
|
||||||
|
|
|
@ -115,7 +115,6 @@ public class Initializer {
|
||||||
// This is used to uniquely identify instance of the SDKSynchronizer. It's used when checking if the Alias is already used or not.
|
// This is used to uniquely identify instance of the SDKSynchronizer. It's used when checking if the Alias is already used or not.
|
||||||
let id = UUID()
|
let id = UUID()
|
||||||
|
|
||||||
let rustBackend: ZcashRustBackendWelding.Type
|
|
||||||
let alias: ZcashSynchronizerAlias
|
let alias: ZcashSynchronizerAlias
|
||||||
let endpoint: LightWalletEndpoint
|
let endpoint: LightWalletEndpoint
|
||||||
let fsBlockDbRoot: URL
|
let fsBlockDbRoot: URL
|
||||||
|
@ -131,6 +130,7 @@ public class Initializer {
|
||||||
let blockDownloaderService: BlockDownloaderService
|
let blockDownloaderService: BlockDownloaderService
|
||||||
let network: ZcashNetwork
|
let network: ZcashNetwork
|
||||||
let logger: Logger
|
let logger: Logger
|
||||||
|
let rustBackend: ZcashRustBackendWelding
|
||||||
|
|
||||||
/// The effective birthday of the wallet based on the height provided when initializing and the checkpoints available on this SDK.
|
/// The effective birthday of the wallet based on the height provided when initializing and the checkpoints available on this SDK.
|
||||||
///
|
///
|
||||||
|
@ -180,8 +180,16 @@ public class Initializer {
|
||||||
let (updatedURLs, parsingError) = Self.tryToUpdateURLs(with: alias, urls: urls)
|
let (updatedURLs, parsingError) = Self.tryToUpdateURLs(with: alias, urls: urls)
|
||||||
|
|
||||||
let logger = OSLogger(logLevel: logLevel, alias: alias)
|
let logger = OSLogger(logLevel: logLevel, alias: alias)
|
||||||
|
let rustBackend = ZcashRustBackend(
|
||||||
|
dbData: updatedURLs.dataDbURL,
|
||||||
|
fsBlockDbRoot: updatedURLs.fsBlockDbRoot,
|
||||||
|
spendParamsPath: updatedURLs.spendParamsURL,
|
||||||
|
outputParamsPath: updatedURLs.outputParamsURL,
|
||||||
|
networkType: network.networkType
|
||||||
|
)
|
||||||
|
|
||||||
self.init(
|
self.init(
|
||||||
rustBackend: ZcashRustBackend.self,
|
rustBackend: rustBackend,
|
||||||
network: network,
|
network: network,
|
||||||
cacheDbURL: cacheDbURL,
|
cacheDbURL: cacheDbURL,
|
||||||
urls: updatedURLs,
|
urls: updatedURLs,
|
||||||
|
@ -198,7 +206,7 @@ public class Initializer {
|
||||||
fsBlockDbRoot: updatedURLs.fsBlockDbRoot,
|
fsBlockDbRoot: updatedURLs.fsBlockDbRoot,
|
||||||
metadataStore: .live(
|
metadataStore: .live(
|
||||||
fsBlockDbRoot: updatedURLs.fsBlockDbRoot,
|
fsBlockDbRoot: updatedURLs.fsBlockDbRoot,
|
||||||
rustBackend: ZcashRustBackend.self,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
@ -216,7 +224,7 @@ public class Initializer {
|
||||||
///
|
///
|
||||||
/// !!! It's expected that URLs put here are already update with the Alias.
|
/// !!! It's expected that URLs put here are already update with the Alias.
|
||||||
init(
|
init(
|
||||||
rustBackend: ZcashRustBackendWelding.Type,
|
rustBackend: ZcashRustBackendWelding,
|
||||||
network: ZcashNetwork,
|
network: ZcashNetwork,
|
||||||
cacheDbURL: URL?,
|
cacheDbURL: URL?,
|
||||||
urls: URLs,
|
urls: URLs,
|
||||||
|
@ -341,7 +349,7 @@ public class Initializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if case .seedRequired = try await rustBackend.initDataDb(dbData: dataDbURL, seed: seed, networkType: network.networkType) {
|
if case .seedRequired = try await rustBackend.initDataDb(seed: seed) {
|
||||||
return .seedRequired
|
return .seedRequired
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -351,12 +359,10 @@ public class Initializer {
|
||||||
let checkpoint = Checkpoint.birthday(with: walletBirthday, network: network)
|
let checkpoint = Checkpoint.birthday(with: walletBirthday, network: network)
|
||||||
do {
|
do {
|
||||||
try await rustBackend.initBlocksTable(
|
try await rustBackend.initBlocksTable(
|
||||||
dbData: dataDbURL,
|
|
||||||
height: Int32(checkpoint.height),
|
height: Int32(checkpoint.height),
|
||||||
hash: checkpoint.hash,
|
hash: checkpoint.hash,
|
||||||
time: checkpoint.time,
|
time: checkpoint.time,
|
||||||
saplingTree: checkpoint.saplingTree,
|
saplingTree: checkpoint.saplingTree
|
||||||
networkType: network.networkType
|
|
||||||
)
|
)
|
||||||
} catch RustWeldingError.dataDbNotEmpty {
|
} catch RustWeldingError.dataDbNotEmpty {
|
||||||
// this is fine
|
// this is fine
|
||||||
|
@ -367,11 +373,7 @@ public class Initializer {
|
||||||
self.walletBirthday = checkpoint.height
|
self.walletBirthday = checkpoint.height
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try await rustBackend.initAccountsTable(
|
try await rustBackend.initAccountsTable(ufvks: viewingKeys)
|
||||||
dbData: dataDbURL,
|
|
||||||
ufvks: viewingKeys,
|
|
||||||
networkType: network.networkType
|
|
||||||
)
|
|
||||||
} catch RustWeldingError.dataDbNotEmpty {
|
} catch RustWeldingError.dataDbNotEmpty {
|
||||||
// this is fine
|
// this is fine
|
||||||
} catch RustWeldingError.malformedStringInput {
|
} catch RustWeldingError.malformedStringInput {
|
||||||
|
@ -395,14 +397,18 @@ public class Initializer {
|
||||||
checks if the provided address is a valid sapling address
|
checks if the provided address is a valid sapling address
|
||||||
*/
|
*/
|
||||||
public func isValidSaplingAddress(_ address: String) -> Bool {
|
public func isValidSaplingAddress(_ address: String) -> Bool {
|
||||||
rustBackend.isValidSaplingAddress(address, networkType: network.networkType)
|
DerivationTool(networkType: network.networkType).isValidSaplingAddress(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
checks if the provided address is a transparent zAddress
|
checks if the provided address is a transparent zAddress
|
||||||
*/
|
*/
|
||||||
public func isValidTransparentAddress(_ address: String) -> Bool {
|
public func isValidTransparentAddress(_ address: String) -> Bool {
|
||||||
rustBackend.isValidTransparentAddress(address, networkType: network.networkType)
|
DerivationTool(networkType: network.networkType).isValidTransparentAddress(address)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeDerivationTool() -> DerivationTool {
|
||||||
|
return DerivationTool(networkType: network.networkType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ public struct UnifiedFullViewingKey: Equatable, StringEncoded, Undescribable {
|
||||||
/// - Throws: `KeyEncodingError.invalidEncoding`when the provided encoding is
|
/// - Throws: `KeyEncodingError.invalidEncoding`when the provided encoding is
|
||||||
/// found to be invalid
|
/// found to be invalid
|
||||||
public init(encoding: String, account: UInt32, network: NetworkType) throws {
|
public init(encoding: String, account: UInt32, network: NetworkType) throws {
|
||||||
guard DerivationTool.rustwelding.isValidUnifiedFullViewingKey(encoding, networkType: network) else {
|
guard DerivationTool(networkType: network).isValidUnifiedFullViewingKey(encoding) else {
|
||||||
throw KeyEncodingError.invalidEncoding
|
throw KeyEncodingError.invalidEncoding
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ public struct SaplingExtendedFullViewingKey: Equatable, StringEncoded, Undescrib
|
||||||
/// - Throws: `KeyEncodingError.invalidEncoding`when the provided encoding is
|
/// - Throws: `KeyEncodingError.invalidEncoding`when the provided encoding is
|
||||||
/// found to be invalid
|
/// found to be invalid
|
||||||
public init(encoding: String, network: NetworkType) throws {
|
public init(encoding: String, network: NetworkType) throws {
|
||||||
guard DerivationTool.rustwelding.isValidSaplingExtendedFullViewingKey(encoding, networkType: network) else {
|
guard ZcashKeyDerivationBackend(networkType: network).isValidSaplingExtendedFullViewingKey(encoding) else {
|
||||||
throw KeyEncodingError.invalidEncoding
|
throw KeyEncodingError.invalidEncoding
|
||||||
}
|
}
|
||||||
self.encoding = encoding
|
self.encoding = encoding
|
||||||
|
@ -174,6 +174,8 @@ public struct SaplingAddress: Equatable, StringEncoded {
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct UnifiedAddress: Equatable, StringEncoded {
|
public struct UnifiedAddress: Equatable, StringEncoded {
|
||||||
|
let networkType: NetworkType
|
||||||
|
|
||||||
public enum Errors: Error {
|
public enum Errors: Error {
|
||||||
case couldNotExtractTypecodes
|
case couldNotExtractTypecodes
|
||||||
}
|
}
|
||||||
|
@ -212,6 +214,7 @@ public struct UnifiedAddress: Equatable, StringEncoded {
|
||||||
/// - Throws: `KeyEncodingError.invalidEncoding`when the provided encoding is
|
/// - Throws: `KeyEncodingError.invalidEncoding`when the provided encoding is
|
||||||
/// found to be invalid
|
/// found to be invalid
|
||||||
public init(encoding: String, network: NetworkType) throws {
|
public init(encoding: String, network: NetworkType) throws {
|
||||||
|
networkType = network
|
||||||
guard DerivationTool(networkType: network).isValidUnifiedAddress(encoding) else {
|
guard DerivationTool(networkType: network).isValidUnifiedAddress(encoding) else {
|
||||||
throw KeyEncodingError.invalidEncoding
|
throw KeyEncodingError.invalidEncoding
|
||||||
}
|
}
|
||||||
|
@ -224,7 +227,7 @@ public struct UnifiedAddress: Equatable, StringEncoded {
|
||||||
/// couldn't be extracted
|
/// couldn't be extracted
|
||||||
public func availableReceiverTypecodes() throws -> [UnifiedAddress.ReceiverTypecodes] {
|
public func availableReceiverTypecodes() throws -> [UnifiedAddress.ReceiverTypecodes] {
|
||||||
do {
|
do {
|
||||||
return try DerivationTool.receiverTypecodesFromUnifiedAddress(self)
|
return try DerivationTool(networkType: networkType).receiverTypecodesFromUnifiedAddress(self)
|
||||||
} catch {
|
} catch {
|
||||||
throw Errors.couldNotExtractTypecodes
|
throw Errors.couldNotExtractTypecodes
|
||||||
}
|
}
|
||||||
|
@ -272,7 +275,7 @@ public enum Recipient: Equatable, StringEncoded {
|
||||||
metadata.networkType)
|
metadata.networkType)
|
||||||
case .p2sh: return (.transparent(TransparentAddress(validatedEncoding: encoded)), metadata.networkType)
|
case .p2sh: return (.transparent(TransparentAddress(validatedEncoding: encoded)), metadata.networkType)
|
||||||
case .sapling: return (.sapling(SaplingAddress(validatedEncoding: encoded)), metadata.networkType)
|
case .sapling: return (.sapling(SaplingAddress(validatedEncoding: encoded)), metadata.networkType)
|
||||||
case .unified: return (.unified(UnifiedAddress(validatedEncoding: encoded)), metadata.networkType)
|
case .unified: return (.unified(UnifiedAddress(validatedEncoding: encoded, networkType: metadata.networkType)), metadata.networkType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,225 @@
|
||||||
|
//
|
||||||
|
// ZcashKeyDerivationBackend.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Francisco Gindre on 4/7/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import libzcashlc
|
||||||
|
|
||||||
|
struct ZcashKeyDerivationBackend: ZcashKeyDerivationBackendWelding {
|
||||||
|
let networkType: NetworkType
|
||||||
|
|
||||||
|
init(networkType: NetworkType) {
|
||||||
|
self.networkType = networkType
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Address metadata and validation
|
||||||
|
static func getAddressMetadata(_ address: String) -> AddressMetadata? {
|
||||||
|
var networkId: UInt32 = 0
|
||||||
|
var addrId: UInt32 = 0
|
||||||
|
guard zcashlc_get_address_metadata(
|
||||||
|
[CChar](address.utf8CString),
|
||||||
|
&networkId,
|
||||||
|
&addrId
|
||||||
|
) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
guard
|
||||||
|
let network = NetworkType.forNetworkId(networkId),
|
||||||
|
let addrType = AddressType.forId(addrId)
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return AddressMetadata(network: network, addrType: addrType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func receiverTypecodesOnUnifiedAddress(_ address: String) throws -> [UInt32] {
|
||||||
|
guard !address.containsCStringNullBytesBeforeStringEnding() else {
|
||||||
|
throw RustWeldingError.invalidInput(message: "`address` contains null bytes.")
|
||||||
|
}
|
||||||
|
|
||||||
|
var len = UInt(0)
|
||||||
|
|
||||||
|
guard let typecodesPointer = zcashlc_get_typecodes_for_unified_address_receivers(
|
||||||
|
[CChar](address.utf8CString),
|
||||||
|
&len
|
||||||
|
), len > 0
|
||||||
|
else {
|
||||||
|
throw RustWeldingError.malformedStringInput
|
||||||
|
}
|
||||||
|
|
||||||
|
var typecodes: [UInt32] = []
|
||||||
|
|
||||||
|
for typecodeIndex in 0 ..< Int(len) {
|
||||||
|
let pointer = typecodesPointer.advanced(by: typecodeIndex)
|
||||||
|
|
||||||
|
typecodes.append(pointer.pointee)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer {
|
||||||
|
zcashlc_free_typecodes(typecodesPointer, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
return typecodes
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidSaplingAddress(_ address: String) -> Bool {
|
||||||
|
guard !address.containsCStringNullBytesBeforeStringEnding() else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return zcashlc_is_valid_shielded_address([CChar](address.utf8CString), networkType.networkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidSaplingExtendedFullViewingKey(_ key: String) -> Bool {
|
||||||
|
guard !key.containsCStringNullBytesBeforeStringEnding() else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return zcashlc_is_valid_viewing_key([CChar](key.utf8CString), networkType.networkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidSaplingExtendedSpendingKey(_ key: String) -> Bool {
|
||||||
|
guard !key.containsCStringNullBytesBeforeStringEnding() else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return zcashlc_is_valid_sapling_extended_spending_key([CChar](key.utf8CString), networkType.networkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidTransparentAddress(_ address: String) -> Bool {
|
||||||
|
guard !address.containsCStringNullBytesBeforeStringEnding() else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return zcashlc_is_valid_transparent_address([CChar](address.utf8CString), networkType.networkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidUnifiedAddress(_ address: String) -> Bool {
|
||||||
|
guard !address.containsCStringNullBytesBeforeStringEnding() else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return zcashlc_is_valid_unified_address([CChar](address.utf8CString), networkType.networkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidUnifiedFullViewingKey(_ key: String) -> Bool {
|
||||||
|
guard !key.containsCStringNullBytesBeforeStringEnding() else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return zcashlc_is_valid_unified_full_viewing_key([CChar](key.utf8CString), networkType.networkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Address Derivation
|
||||||
|
|
||||||
|
func deriveUnifiedSpendingKey(
|
||||||
|
from seed: [UInt8],
|
||||||
|
accountIndex: Int32
|
||||||
|
) async throws -> UnifiedSpendingKey {
|
||||||
|
let binaryKeyPtr = seed.withUnsafeBufferPointer { seedBufferPtr in
|
||||||
|
return zcashlc_derive_spending_key(
|
||||||
|
seedBufferPtr.baseAddress,
|
||||||
|
UInt(seed.count),
|
||||||
|
accountIndex,
|
||||||
|
networkType.networkId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer { zcashlc_free_binary_key(binaryKeyPtr) }
|
||||||
|
|
||||||
|
guard let binaryKey = binaryKeyPtr?.pointee else {
|
||||||
|
throw lastError() ?? .genericError(message: "No error message available")
|
||||||
|
}
|
||||||
|
|
||||||
|
return binaryKey.unsafeToUnifiedSpendingKey(network: networkType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deriveUnifiedFullViewingKey(from spendingKey: UnifiedSpendingKey) async throws -> UnifiedFullViewingKey {
|
||||||
|
let extfvk = try spendingKey.bytes.withUnsafeBufferPointer { uskBufferPtr -> UnsafeMutablePointer<CChar> in
|
||||||
|
guard let extfvk = zcashlc_spending_key_to_full_viewing_key(
|
||||||
|
uskBufferPtr.baseAddress,
|
||||||
|
UInt(spendingKey.bytes.count),
|
||||||
|
networkType.networkId
|
||||||
|
) else {
|
||||||
|
throw lastError() ?? .genericError(message: "No error message available")
|
||||||
|
}
|
||||||
|
|
||||||
|
return extfvk
|
||||||
|
}
|
||||||
|
|
||||||
|
defer { zcashlc_string_free(extfvk) }
|
||||||
|
|
||||||
|
guard let derived = String(validatingUTF8: extfvk) else {
|
||||||
|
throw RustWeldingError.unableToDeriveKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
return UnifiedFullViewingKey(validatedEncoding: derived, account: spendingKey.account)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSaplingReceiver(for uAddr: UnifiedAddress) throws -> SaplingAddress {
|
||||||
|
guard let saplingCStr = zcashlc_get_sapling_receiver_for_unified_address(
|
||||||
|
[CChar](uAddr.encoding.utf8CString)
|
||||||
|
) else {
|
||||||
|
throw KeyDerivationErrors.invalidUnifiedAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
defer { zcashlc_string_free(saplingCStr) }
|
||||||
|
|
||||||
|
guard let saplingReceiverStr = String(validatingUTF8: saplingCStr) else {
|
||||||
|
throw KeyDerivationErrors.receiverNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return SaplingAddress(validatedEncoding: saplingReceiverStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTransparentReceiver(for uAddr: UnifiedAddress) throws -> TransparentAddress {
|
||||||
|
guard let transparentCStr = zcashlc_get_transparent_receiver_for_unified_address(
|
||||||
|
[CChar](uAddr.encoding.utf8CString)
|
||||||
|
) else {
|
||||||
|
throw KeyDerivationErrors.invalidUnifiedAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
defer { zcashlc_string_free(transparentCStr) }
|
||||||
|
|
||||||
|
guard let transparentReceiverStr = String(validatingUTF8: transparentCStr) else {
|
||||||
|
throw KeyDerivationErrors.receiverNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return TransparentAddress(validatedEncoding: transparentReceiverStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Error Handling
|
||||||
|
|
||||||
|
private func lastError() -> RustWeldingError? {
|
||||||
|
defer { zcashlc_clear_last_error() }
|
||||||
|
|
||||||
|
guard let message = getLastError() else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if message.contains("couldn't load Sapling spend parameters") {
|
||||||
|
return RustWeldingError.saplingSpendParametersNotFound
|
||||||
|
} else if message.contains("is not empty") {
|
||||||
|
return RustWeldingError.dataDbNotEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
return RustWeldingError.genericError(message: message)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getLastError() -> String? {
|
||||||
|
let errorLen = zcashlc_last_error_length()
|
||||||
|
if errorLen > 0 {
|
||||||
|
let error = UnsafeMutablePointer<Int8>.allocate(capacity: Int(errorLen))
|
||||||
|
zcashlc_error_message_utf8(error, errorLen)
|
||||||
|
zcashlc_clear_last_error()
|
||||||
|
return String(validatingUTF8: error)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
//
|
||||||
|
// ZcashKeyDerivationBackendWelding.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Michal Fousek on 11.04.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
protocol ZcashKeyDerivationBackendWelding {
|
||||||
|
/// The network type this `ZcashKeyDerivationBackendWelding` implementation is for
|
||||||
|
var networkType: NetworkType { get }
|
||||||
|
|
||||||
|
/// Returns the network and address type for the given Zcash address string,
|
||||||
|
/// if the string represents a valid Zcash address.
|
||||||
|
/// - Note: not `NetworkType` bound
|
||||||
|
static func getAddressMetadata(_ address: String) -> AddressMetadata?
|
||||||
|
|
||||||
|
/// Obtains the available receiver typecodes for the given String encoded Unified Address
|
||||||
|
/// - Parameter address: public key represented as a String
|
||||||
|
/// - Returns the `[UInt32]` that compose the given UA
|
||||||
|
/// - Throws `RustWeldingError.invalidInput(message: String)` when the UA is either invalid or malformed
|
||||||
|
/// - Note: not `NetworkType` bound
|
||||||
|
func receiverTypecodesOnUnifiedAddress(_ address: String) throws -> [UInt32]
|
||||||
|
|
||||||
|
/// Validates the if the given string is a valid Sapling Address
|
||||||
|
/// - Parameter address: UTF-8 encoded String to validate
|
||||||
|
/// - Returns: true when the address is valid. Returns false in any other case
|
||||||
|
/// - Throws: Error when the provided address belongs to another network
|
||||||
|
func isValidSaplingAddress(_ address: String) -> Bool
|
||||||
|
|
||||||
|
/// Validates the if the given string is a valid Sapling Extended Full Viewing Key
|
||||||
|
/// - Parameter key: UTF-8 encoded String to validate
|
||||||
|
/// - Returns: `true` when the Sapling Extended Full Viewing Key is valid. `false` in any other case
|
||||||
|
/// - Throws: Error when there's another problem not related to validity of the string in question
|
||||||
|
func isValidSaplingExtendedFullViewingKey(_ key: String) -> Bool
|
||||||
|
|
||||||
|
/// Validates the if the given string is a valid Sapling Extended Spending Key
|
||||||
|
/// - Returns: `true` when the Sapling Extended Spending Key is valid, false in any other case.
|
||||||
|
/// - Throws: Error when the key is semantically valid but it belongs to another network
|
||||||
|
/// - parameter key: String encoded Extended Spending Key
|
||||||
|
func isValidSaplingExtendedSpendingKey(_ key: String) -> Bool
|
||||||
|
|
||||||
|
/// Validates the if the given string is a valid Transparent Address
|
||||||
|
/// - Parameter address: UTF-8 encoded String to validate
|
||||||
|
/// - Returns: true when the address is valid and transparent. false in any other case
|
||||||
|
func isValidTransparentAddress(_ address: String) -> Bool
|
||||||
|
|
||||||
|
/// validates whether a string encoded address is a valid Unified Address.
|
||||||
|
/// - Parameter address: UTF-8 encoded String to validate
|
||||||
|
/// - Returns: true when the address is valid and transparent. false in any other case
|
||||||
|
func isValidUnifiedAddress(_ address: String) -> Bool
|
||||||
|
|
||||||
|
/// verifies that the given string-encoded `UnifiedFullViewingKey` is valid.
|
||||||
|
/// - Parameter ufvk: UTF-8 encoded String to validate
|
||||||
|
/// - Returns: true when the encoded string is a valid UFVK. false in any other case
|
||||||
|
func isValidUnifiedFullViewingKey(_ ufvk: String) -> Bool
|
||||||
|
|
||||||
|
/// Derives and returns a unified spending key from the given seed for the given account ID.
|
||||||
|
/// Returns the binary encoding of the spending key. The caller should manage the memory of (and store, if necessary) the returned spending key in a secure fashion.
|
||||||
|
/// - Parameter seed: a Byte Array with the seed
|
||||||
|
/// - Parameter accountIndex:account index that the key can spend from
|
||||||
|
func deriveUnifiedSpendingKey(from seed: [UInt8], accountIndex: Int32) async throws -> UnifiedSpendingKey
|
||||||
|
|
||||||
|
/// Derives a `UnifiedFullViewingKey` from a `UnifiedSpendingKey`
|
||||||
|
/// - Parameter spendingKey: the `UnifiedSpendingKey` to derive from
|
||||||
|
/// - Throws: `RustWeldingError.unableToDeriveKeys` if the SDK couldn't derive the UFVK.
|
||||||
|
/// - Returns: the derived `UnifiedFullViewingKey`
|
||||||
|
func deriveUnifiedFullViewingKey(from spendingKey: UnifiedSpendingKey) async throws -> UnifiedFullViewingKey
|
||||||
|
|
||||||
|
/// Returns the Sapling receiver within the given Unified Address, if any.
|
||||||
|
/// - Parameter uAddr: a `UnifiedAddress`
|
||||||
|
/// - Returns a `SaplingAddress` if any
|
||||||
|
/// - Throws `receiverNotFound` when the receiver is not found. `invalidUnifiedAddress` if the UA provided is not valid
|
||||||
|
func getSaplingReceiver(for uAddr: UnifiedAddress) throws -> SaplingAddress
|
||||||
|
|
||||||
|
/// Returns the transparent receiver within the given Unified Address, if any.
|
||||||
|
/// - parameter uAddr: a `UnifiedAddress`
|
||||||
|
/// - Returns a `TransparentAddress` if any
|
||||||
|
/// - Throws `receiverNotFound` when the receiver is not found. `invalidUnifiedAddress` if the UA provided is not valid
|
||||||
|
func getTransparentReceiver(for uAddr: UnifiedAddress) throws -> TransparentAddress
|
||||||
|
}
|
|
@ -9,12 +9,37 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import libzcashlc
|
import libzcashlc
|
||||||
|
|
||||||
class ZcashRustBackend: ZcashRustBackendWelding {
|
actor ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
static let minimumConfirmations: UInt32 = 10
|
let minimumConfirmations: UInt32 = 10
|
||||||
static let useZIP317Fees = false
|
let useZIP317Fees = false
|
||||||
static func createAccount(dbData: URL, seed: [UInt8], networkType: NetworkType) async throws -> UnifiedSpendingKey {
|
|
||||||
let dbData = dbData.osStr()
|
|
||||||
|
|
||||||
|
let dbData: (String, UInt)
|
||||||
|
let fsBlockDbRoot: (String, UInt)
|
||||||
|
let spendParamsPath: (String, UInt)
|
||||||
|
let outputParamsPath: (String, UInt)
|
||||||
|
let keyDeriving: ZcashKeyDerivationBackendWelding
|
||||||
|
|
||||||
|
nonisolated let networkType: NetworkType
|
||||||
|
|
||||||
|
/// Creates instance of `ZcashRustBackend`.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - dbData: `URL` pointing to file where data database will be.
|
||||||
|
/// - fsBlockDbRoot: `URL` pointing to the filesystem root directory where the fsBlock cache is.
|
||||||
|
/// this directory is expected to contain a `/blocks` sub-directory with the blocks stored in the convened filename
|
||||||
|
/// format `{height}-{hash}-block`. This directory has must be granted both write and read permissions.
|
||||||
|
/// - spendParamsPath: `URL` pointing to spend parameters file.
|
||||||
|
/// - outputParamsPath: `URL` pointing to output parameters file.
|
||||||
|
/// - networkType: Network type to use.
|
||||||
|
init(dbData: URL, fsBlockDbRoot: URL, spendParamsPath: URL, outputParamsPath: URL, networkType: NetworkType) {
|
||||||
|
self.dbData = dbData.osStr()
|
||||||
|
self.fsBlockDbRoot = fsBlockDbRoot.osPathStr()
|
||||||
|
self.spendParamsPath = spendParamsPath.osPathStr()
|
||||||
|
self.outputParamsPath = outputParamsPath.osPathStr()
|
||||||
|
self.networkType = networkType
|
||||||
|
self.keyDeriving = ZcashKeyDerivationBackend(networkType: networkType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createAccount(seed: [UInt8]) async throws -> UnifiedSpendingKey {
|
||||||
guard let ffiBinaryKeyPtr = zcashlc_create_account(
|
guard let ffiBinaryKeyPtr = zcashlc_create_account(
|
||||||
dbData.0,
|
dbData.0,
|
||||||
dbData.1,
|
dbData.1,
|
||||||
|
@ -30,20 +55,13 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
return ffiBinaryKeyPtr.pointee.unsafeToUnifiedSpendingKey(network: networkType)
|
return ffiBinaryKeyPtr.pointee.unsafeToUnifiedSpendingKey(network: networkType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// swiftlint:disable function_parameter_count
|
func createToAddress(
|
||||||
static func createToAddress(
|
|
||||||
dbData: URL,
|
|
||||||
usk: UnifiedSpendingKey,
|
usk: UnifiedSpendingKey,
|
||||||
to address: String,
|
to address: String,
|
||||||
value: Int64,
|
value: Int64,
|
||||||
memo: MemoBytes?,
|
memo: MemoBytes?
|
||||||
spendParamsPath: String,
|
) async throws -> Int64 {
|
||||||
outputParamsPath: String,
|
let result = usk.bytes.withUnsafeBufferPointer { uskPtr in
|
||||||
networkType: NetworkType
|
|
||||||
) async -> Int64 {
|
|
||||||
let dbData = dbData.osStr()
|
|
||||||
|
|
||||||
return usk.bytes.withUnsafeBufferPointer { uskPtr in
|
|
||||||
zcashlc_create_to_address(
|
zcashlc_create_to_address(
|
||||||
dbData.0,
|
dbData.0,
|
||||||
dbData.1,
|
dbData.1,
|
||||||
|
@ -52,55 +70,39 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
[CChar](address.utf8CString),
|
[CChar](address.utf8CString),
|
||||||
value,
|
value,
|
||||||
memo?.bytes,
|
memo?.bytes,
|
||||||
spendParamsPath,
|
spendParamsPath.0,
|
||||||
UInt(spendParamsPath.lengthOfBytes(using: .utf8)),
|
spendParamsPath.1,
|
||||||
outputParamsPath,
|
outputParamsPath.0,
|
||||||
UInt(outputParamsPath.lengthOfBytes(using: .utf8)),
|
outputParamsPath.1,
|
||||||
networkType.networkId,
|
networkType.networkId,
|
||||||
minimumConfirmations,
|
minimumConfirmations,
|
||||||
useZIP317Fees
|
useZIP317Fees
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guard result > 0 else {
|
||||||
|
throw lastError() ?? .genericError(message: "No error message available")
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
static func decryptAndStoreTransaction(dbData: URL, txBytes: [UInt8], minedHeight: Int32, networkType: NetworkType) async -> Bool {
|
func decryptAndStoreTransaction(txBytes: [UInt8], minedHeight: Int32) async throws {
|
||||||
let dbData = dbData.osStr()
|
let result = zcashlc_decrypt_and_store_transaction(
|
||||||
return zcashlc_decrypt_and_store_transaction(
|
|
||||||
dbData.0,
|
dbData.0,
|
||||||
dbData.1,
|
dbData.1,
|
||||||
txBytes,
|
txBytes,
|
||||||
UInt(txBytes.count),
|
UInt(txBytes.count),
|
||||||
UInt32(minedHeight),
|
UInt32(minedHeight),
|
||||||
networkType.networkId
|
networkType.networkId
|
||||||
) != 0
|
)
|
||||||
}
|
|
||||||
|
|
||||||
static func deriveUnifiedSpendingKey(
|
guard result != 0 else {
|
||||||
from seed: [UInt8],
|
|
||||||
accountIndex: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) throws -> UnifiedSpendingKey {
|
|
||||||
let binaryKeyPtr = seed.withUnsafeBufferPointer { seedBufferPtr in
|
|
||||||
return zcashlc_derive_spending_key(
|
|
||||||
seedBufferPtr.baseAddress,
|
|
||||||
UInt(seed.count),
|
|
||||||
accountIndex,
|
|
||||||
networkType.networkId
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer { zcashlc_free_binary_key(binaryKeyPtr) }
|
|
||||||
|
|
||||||
guard let binaryKey = binaryKeyPtr?.pointee else {
|
|
||||||
throw lastError() ?? .genericError(message: "No error message available")
|
throw lastError() ?? .genericError(message: "No error message available")
|
||||||
}
|
}
|
||||||
|
|
||||||
return binaryKey.unsafeToUnifiedSpendingKey(network: networkType)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getBalance(dbData: URL, account: Int32, networkType: NetworkType) async throws -> Int64 {
|
func getBalance(account: Int32) async throws -> Int64 {
|
||||||
let dbData = dbData.osStr()
|
|
||||||
|
|
||||||
let balance = zcashlc_get_balance(dbData.0, dbData.1, account, networkType.networkId)
|
let balance = zcashlc_get_balance(dbData.0, dbData.1, account, networkType.networkId)
|
||||||
|
|
||||||
guard balance >= 0 else {
|
guard balance >= 0 else {
|
||||||
|
@ -110,13 +112,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
return balance
|
return balance
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getCurrentAddress(
|
func getCurrentAddress(account: Int32) async throws -> UnifiedAddress {
|
||||||
dbData: URL,
|
|
||||||
account: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws -> UnifiedAddress {
|
|
||||||
let dbData = dbData.osStr()
|
|
||||||
|
|
||||||
guard let addressCStr = zcashlc_get_current_address(
|
guard let addressCStr = zcashlc_get_current_address(
|
||||||
dbData.0,
|
dbData.0,
|
||||||
dbData.1,
|
dbData.1,
|
||||||
|
@ -132,31 +128,25 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
throw RustWeldingError.unableToDeriveKeys
|
throw RustWeldingError.unableToDeriveKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
return UnifiedAddress(validatedEncoding: address)
|
return UnifiedAddress(validatedEncoding: address, networkType: networkType)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getNearestRewindHeight(
|
func getNearestRewindHeight(height: Int32) async throws -> Int32 {
|
||||||
dbData: URL,
|
let result = zcashlc_get_nearest_rewind_height(
|
||||||
height: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async -> Int32 {
|
|
||||||
let dbData = dbData.osStr()
|
|
||||||
|
|
||||||
return zcashlc_get_nearest_rewind_height(
|
|
||||||
dbData.0,
|
dbData.0,
|
||||||
dbData.1,
|
dbData.1,
|
||||||
height,
|
height,
|
||||||
networkType.networkId
|
networkType.networkId
|
||||||
)
|
)
|
||||||
|
|
||||||
|
guard result > 0 else {
|
||||||
|
throw lastError() ?? .genericError(message: "No error message available")
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getNextAvailableAddress(
|
func getNextAvailableAddress(account: Int32) async throws -> UnifiedAddress {
|
||||||
dbData: URL,
|
|
||||||
account: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws -> UnifiedAddress {
|
|
||||||
let dbData = dbData.osStr()
|
|
||||||
|
|
||||||
guard let addressCStr = zcashlc_get_next_available_address(
|
guard let addressCStr = zcashlc_get_next_available_address(
|
||||||
dbData.0,
|
dbData.0,
|
||||||
dbData.1,
|
dbData.1,
|
||||||
|
@ -172,16 +162,10 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
throw RustWeldingError.unableToDeriveKeys
|
throw RustWeldingError.unableToDeriveKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
return UnifiedAddress(validatedEncoding: address)
|
return UnifiedAddress(validatedEncoding: address, networkType: networkType)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getReceivedMemo(
|
func getReceivedMemo(idNote: Int64) async -> Memo? {
|
||||||
dbData: URL,
|
|
||||||
idNote: Int64,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async -> Memo? {
|
|
||||||
let dbData = dbData.osStr()
|
|
||||||
|
|
||||||
var contiguousMemoBytes = ContiguousArray<UInt8>(MemoBytes.empty().bytes)
|
var contiguousMemoBytes = ContiguousArray<UInt8>(MemoBytes.empty().bytes)
|
||||||
var success = false
|
var success = false
|
||||||
|
|
||||||
|
@ -194,29 +178,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
return (try? MemoBytes(contiguousBytes: contiguousMemoBytes)).flatMap { try? $0.intoMemo() }
|
return (try? MemoBytes(contiguousBytes: contiguousMemoBytes)).flatMap { try? $0.intoMemo() }
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getSaplingReceiver(for uAddr: UnifiedAddress) throws -> SaplingAddress {
|
func getSentMemo(idNote: Int64) async -> Memo? {
|
||||||
guard let saplingCStr = zcashlc_get_sapling_receiver_for_unified_address(
|
|
||||||
[CChar](uAddr.encoding.utf8CString)
|
|
||||||
) else {
|
|
||||||
throw KeyDerivationErrors.invalidUnifiedAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
defer { zcashlc_string_free(saplingCStr) }
|
|
||||||
|
|
||||||
guard let saplingReceiverStr = String(validatingUTF8: saplingCStr) else {
|
|
||||||
throw KeyDerivationErrors.receiverNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
return SaplingAddress(validatedEncoding: saplingReceiverStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func getSentMemo(
|
|
||||||
dbData: URL,
|
|
||||||
idNote: Int64,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async -> Memo? {
|
|
||||||
let dbData = dbData.osStr()
|
|
||||||
|
|
||||||
var contiguousMemoBytes = ContiguousArray<UInt8>(MemoBytes.empty().bytes)
|
var contiguousMemoBytes = ContiguousArray<UInt8>(MemoBytes.empty().bytes)
|
||||||
var success = false
|
var success = false
|
||||||
|
|
||||||
|
@ -229,16 +191,11 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
return (try? MemoBytes(contiguousBytes: contiguousMemoBytes)).flatMap { try? $0.intoMemo() }
|
return (try? MemoBytes(contiguousBytes: contiguousMemoBytes)).flatMap { try? $0.intoMemo() }
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getTransparentBalance(
|
func getTransparentBalance(account: Int32) async throws -> Int64 {
|
||||||
dbData: URL,
|
|
||||||
account: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws -> Int64 {
|
|
||||||
guard account >= 0 else {
|
guard account >= 0 else {
|
||||||
throw RustWeldingError.invalidInput(message: "Account index must be non-negative")
|
throw RustWeldingError.invalidInput(message: "Account index must be non-negative")
|
||||||
}
|
}
|
||||||
|
|
||||||
let dbData = dbData.osStr()
|
|
||||||
let balance = zcashlc_get_total_transparent_balance_for_account(
|
let balance = zcashlc_get_total_transparent_balance_for_account(
|
||||||
dbData.0,
|
dbData.0,
|
||||||
dbData.1,
|
dbData.1,
|
||||||
|
@ -253,8 +210,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
return balance
|
return balance
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getVerifiedBalance(dbData: URL, account: Int32, networkType: NetworkType) async throws -> Int64 {
|
func getVerifiedBalance(account: Int32) async throws -> Int64 {
|
||||||
let dbData = dbData.osStr()
|
|
||||||
let balance = zcashlc_get_verified_balance(
|
let balance = zcashlc_get_verified_balance(
|
||||||
dbData.0,
|
dbData.0,
|
||||||
dbData.1,
|
dbData.1,
|
||||||
|
@ -270,17 +226,11 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
return balance
|
return balance
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getVerifiedTransparentBalance(
|
func getVerifiedTransparentBalance(account: Int32) async throws -> Int64 {
|
||||||
dbData: URL,
|
|
||||||
account: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws -> Int64 {
|
|
||||||
guard account >= 0 else {
|
guard account >= 0 else {
|
||||||
throw RustWeldingError.invalidInput(message: "`account` must be non-negative")
|
throw RustWeldingError.invalidInput(message: "`account` must be non-negative")
|
||||||
}
|
}
|
||||||
|
|
||||||
let dbData = dbData.osStr()
|
|
||||||
|
|
||||||
let balance = zcashlc_get_verified_transparent_balance_for_account(
|
let balance = zcashlc_get_verified_transparent_balance_for_account(
|
||||||
dbData.0,
|
dbData.0,
|
||||||
dbData.1,
|
dbData.1,
|
||||||
|
@ -299,8 +249,8 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
|
|
||||||
return balance
|
return balance
|
||||||
}
|
}
|
||||||
|
|
||||||
static func lastError() -> RustWeldingError? {
|
private nonisolated func lastError() -> RustWeldingError? {
|
||||||
defer { zcashlc_clear_last_error() }
|
defer { zcashlc_clear_last_error() }
|
||||||
|
|
||||||
guard let message = getLastError() else {
|
guard let message = getLastError() else {
|
||||||
|
@ -316,43 +266,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
return RustWeldingError.genericError(message: message)
|
return RustWeldingError.genericError(message: message)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getAddressMetadata(_ address: String) -> AddressMetadata? {
|
private nonisolated func getLastError() -> String? {
|
||||||
var networkId: UInt32 = 0
|
|
||||||
var addrId: UInt32 = 0
|
|
||||||
guard zcashlc_get_address_metadata(
|
|
||||||
[CChar](address.utf8CString),
|
|
||||||
&networkId,
|
|
||||||
&addrId
|
|
||||||
) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let network = NetworkType.forNetworkId(networkId),
|
|
||||||
let addrType = AddressType.forId(addrId)
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return AddressMetadata(network: network, addrType: addrType)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func getTransparentReceiver(for uAddr: UnifiedAddress) throws -> TransparentAddress {
|
|
||||||
guard let transparentCStr = zcashlc_get_transparent_receiver_for_unified_address(
|
|
||||||
[CChar](uAddr.encoding.utf8CString)
|
|
||||||
) else {
|
|
||||||
throw KeyDerivationErrors.invalidUnifiedAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
defer { zcashlc_string_free(transparentCStr) }
|
|
||||||
|
|
||||||
guard let transparentReceiverStr = String(validatingUTF8: transparentCStr) else {
|
|
||||||
throw KeyDerivationErrors.receiverNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
return TransparentAddress(validatedEncoding: transparentReceiverStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func getLastError() -> String? {
|
|
||||||
let errorLen = zcashlc_last_error_length()
|
let errorLen = zcashlc_last_error_length()
|
||||||
if errorLen > 0 {
|
if errorLen > 0 {
|
||||||
let error = UnsafeMutablePointer<Int8>.allocate(capacity: Int(errorLen))
|
let error = UnsafeMutablePointer<Int8>.allocate(capacity: Int(errorLen))
|
||||||
|
@ -364,8 +278,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func initDataDb(dbData: URL, seed: [UInt8]?, networkType: NetworkType) async throws -> DbInitResult {
|
func initDataDb(seed: [UInt8]?) async throws -> DbInitResult {
|
||||||
let dbData = dbData.osStr()
|
|
||||||
switch zcashlc_init_data_database(dbData.0, dbData.1, seed, UInt(seed?.count ?? 0), networkType.networkId) {
|
switch zcashlc_init_data_database(dbData.0, dbData.1, seed, UInt(seed?.count ?? 0), networkType.networkId) {
|
||||||
case 0: // ok
|
case 0: // ok
|
||||||
return DbInitResult.success
|
return DbInitResult.success
|
||||||
|
@ -375,74 +288,20 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
throw throwDataDbError(lastError() ?? .genericError(message: "No error message found"))
|
throw throwDataDbError(lastError() ?? .genericError(message: "No error message found"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func isValidSaplingAddress(_ address: String, networkType: NetworkType) -> Bool {
|
|
||||||
guard !address.containsCStringNullBytesBeforeStringEnding() else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return zcashlc_is_valid_shielded_address([CChar](address.utf8CString), networkType.networkId)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func isValidTransparentAddress(_ address: String, networkType: NetworkType) -> Bool {
|
|
||||||
guard !address.containsCStringNullBytesBeforeStringEnding() else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return zcashlc_is_valid_transparent_address([CChar](address.utf8CString), networkType.networkId)
|
func initAccountsTable(ufvks: [UnifiedFullViewingKey]) async throws {
|
||||||
}
|
|
||||||
|
|
||||||
static func isValidSaplingExtendedFullViewingKey(_ key: String, networkType: NetworkType) -> Bool {
|
|
||||||
guard !key.containsCStringNullBytesBeforeStringEnding() else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return zcashlc_is_valid_viewing_key([CChar](key.utf8CString), networkType.networkId)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func isValidSaplingExtendedSpendingKey(_ key: String, networkType: NetworkType) -> Bool {
|
|
||||||
guard !key.containsCStringNullBytesBeforeStringEnding() else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return zcashlc_is_valid_sapling_extended_spending_key([CChar](key.utf8CString), networkType.networkId)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func isValidUnifiedAddress(_ address: String, networkType: NetworkType) -> Bool {
|
|
||||||
guard !address.containsCStringNullBytesBeforeStringEnding() else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return zcashlc_is_valid_unified_address([CChar](address.utf8CString), networkType.networkId)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func isValidUnifiedFullViewingKey(_ key: String, networkType: NetworkType) -> Bool {
|
|
||||||
guard !key.containsCStringNullBytesBeforeStringEnding() else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return zcashlc_is_valid_unified_full_viewing_key([CChar](key.utf8CString), networkType.networkId)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func initAccountsTable(
|
|
||||||
dbData: URL,
|
|
||||||
ufvks: [UnifiedFullViewingKey],
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws {
|
|
||||||
let dbData = dbData.osStr()
|
|
||||||
|
|
||||||
var ffiUfvks: [FFIEncodedKey] = []
|
var ffiUfvks: [FFIEncodedKey] = []
|
||||||
for ufvk in ufvks {
|
for ufvk in ufvks {
|
||||||
guard !ufvk.encoding.containsCStringNullBytesBeforeStringEnding() else {
|
guard !ufvk.encoding.containsCStringNullBytesBeforeStringEnding() else {
|
||||||
throw RustWeldingError.invalidInput(message: "`UFVK` contains null bytes.")
|
throw RustWeldingError.invalidInput(message: "`UFVK` contains null bytes.")
|
||||||
}
|
}
|
||||||
|
|
||||||
guard self.isValidUnifiedFullViewingKey(ufvk.encoding, networkType: networkType) else {
|
guard self.keyDeriving.isValidUnifiedFullViewingKey(ufvk.encoding) else {
|
||||||
throw RustWeldingError.invalidInput(message: "UFVK is invalid.")
|
throw RustWeldingError.invalidInput(message: "UFVK is invalid.")
|
||||||
}
|
}
|
||||||
|
|
||||||
let ufvkCStr = [CChar](String(ufvk.encoding).utf8CString)
|
let ufvkCStr = [CChar](String(ufvk.encoding).utf8CString)
|
||||||
|
|
||||||
let ufvkPtr = UnsafeMutablePointer<CChar>.allocate(capacity: ufvkCStr.count)
|
let ufvkPtr = UnsafeMutablePointer<CChar>.allocate(capacity: ufvkCStr.count)
|
||||||
ufvkPtr.initialize(from: ufvkCStr, count: ufvkCStr.count)
|
ufvkPtr.initialize(from: ufvkCStr, count: ufvkCStr.count)
|
||||||
|
|
||||||
|
@ -476,19 +335,15 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func initBlockMetadataDb(fsBlockDbRoot: URL) async throws -> Bool {
|
func initBlockMetadataDb() async throws {
|
||||||
let blockDb = fsBlockDbRoot.osPathStr()
|
let result = zcashlc_init_block_metadata_db(fsBlockDbRoot.0, fsBlockDbRoot.1)
|
||||||
|
|
||||||
let result = zcashlc_init_block_metadata_db(blockDb.0, blockDb.1)
|
|
||||||
|
|
||||||
guard result else {
|
guard result else {
|
||||||
throw lastError() ?? .genericError(message: "`initAccountsTable` failed with unknown error")
|
throw lastError() ?? .genericError(message: "`initAccountsTable` failed with unknown error")
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static func writeBlocksMetadata(fsBlockDbRoot: URL, blocks: [ZcashCompactBlock]) async throws -> Bool {
|
func writeBlocksMetadata(blocks: [ZcashCompactBlock]) async throws {
|
||||||
var ffiBlockMetaVec: [FFIBlockMeta] = []
|
var ffiBlockMetaVec: [FFIBlockMeta] = []
|
||||||
|
|
||||||
for block in blocks {
|
for block in blocks {
|
||||||
|
@ -507,7 +362,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
hashPtr.deallocate()
|
hashPtr.deallocate()
|
||||||
ffiBlockMetaVec.deallocateElements()
|
ffiBlockMetaVec.deallocateElements()
|
||||||
}
|
}
|
||||||
return false
|
throw RustWeldingError.writeBlocksMetadataAllocationProblem
|
||||||
}
|
}
|
||||||
|
|
||||||
ffiBlockMetaVec.append(
|
ffiBlockMetaVec.append(
|
||||||
|
@ -530,50 +385,35 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
|
|
||||||
defer { ffiBlockMetaVec.deallocateElements() }
|
defer { ffiBlockMetaVec.deallocateElements() }
|
||||||
|
|
||||||
let result = try contiguousFFIBlocks.withContiguousMutableStorageIfAvailable { ptr in
|
try contiguousFFIBlocks.withContiguousMutableStorageIfAvailable { ptr in
|
||||||
var meta = FFIBlocksMeta()
|
var meta = FFIBlocksMeta()
|
||||||
meta.ptr = ptr.baseAddress
|
meta.ptr = ptr.baseAddress
|
||||||
meta.len = len
|
meta.len = len
|
||||||
|
|
||||||
fsBlocks.initialize(to: meta)
|
fsBlocks.initialize(to: meta)
|
||||||
|
|
||||||
let fsDb = fsBlockDbRoot.osPathStr()
|
let res = zcashlc_write_block_metadata(fsBlockDbRoot.0, fsBlockDbRoot.1, fsBlocks)
|
||||||
|
|
||||||
let res = zcashlc_write_block_metadata(fsDb.0, fsDb.1, fsBlocks)
|
|
||||||
|
|
||||||
guard res else {
|
guard res else {
|
||||||
throw lastError() ?? RustWeldingError.genericError(message: "failed to write block metadata")
|
throw lastError() ?? RustWeldingError.genericError(message: "failed to write block metadata")
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let value = result else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// swiftlint:disable function_parameter_count
|
func initBlocksTable(
|
||||||
static func initBlocksTable(
|
|
||||||
dbData: URL,
|
|
||||||
height: Int32,
|
height: Int32,
|
||||||
hash: String,
|
hash: String,
|
||||||
time: UInt32,
|
time: UInt32,
|
||||||
saplingTree: String,
|
saplingTree: String
|
||||||
networkType: NetworkType
|
|
||||||
) async throws {
|
) async throws {
|
||||||
let dbData = dbData.osStr()
|
|
||||||
|
|
||||||
guard !hash.containsCStringNullBytesBeforeStringEnding() else {
|
guard !hash.containsCStringNullBytesBeforeStringEnding() else {
|
||||||
throw RustWeldingError.invalidInput(message: "`hash` contains null bytes.")
|
throw RustWeldingError.invalidInput(message: "`hash` contains null bytes.")
|
||||||
}
|
}
|
||||||
|
|
||||||
guard !saplingTree.containsCStringNullBytesBeforeStringEnding() else {
|
guard !saplingTree.containsCStringNullBytesBeforeStringEnding() else {
|
||||||
throw RustWeldingError.invalidInput(message: "`saplingTree` contains null bytes.")
|
throw RustWeldingError.invalidInput(message: "`saplingTree` contains null bytes.")
|
||||||
}
|
}
|
||||||
|
|
||||||
guard zcashlc_init_blocks_table(
|
guard zcashlc_init_blocks_table(
|
||||||
dbData.0,
|
dbData.0,
|
||||||
dbData.1,
|
dbData.1,
|
||||||
|
@ -587,19 +427,11 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func latestCachedBlockHeight(fsBlockDbRoot: URL) async -> BlockHeight {
|
func latestCachedBlockHeight() async -> BlockHeight {
|
||||||
let fsBlockDb = fsBlockDbRoot.osPathStr()
|
return BlockHeight(zcashlc_latest_cached_block_height(fsBlockDbRoot.0, fsBlockDbRoot.1))
|
||||||
|
|
||||||
return BlockHeight(zcashlc_latest_cached_block_height(fsBlockDb.0, fsBlockDb.1))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static func listTransparentReceivers(
|
func listTransparentReceivers(account: Int32) async throws -> [TransparentAddress] {
|
||||||
dbData: URL,
|
|
||||||
account: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws -> [TransparentAddress] {
|
|
||||||
let dbData = dbData.osStr()
|
|
||||||
|
|
||||||
guard let encodedKeysPtr = zcashlc_list_transparent_receivers(
|
guard let encodedKeysPtr = zcashlc_list_transparent_receivers(
|
||||||
dbData.0,
|
dbData.0,
|
||||||
dbData.1,
|
dbData.1,
|
||||||
|
@ -627,18 +459,14 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
|
|
||||||
return addresses
|
return addresses
|
||||||
}
|
}
|
||||||
|
|
||||||
static func putUnspentTransparentOutput(
|
func putUnspentTransparentOutput(
|
||||||
dbData: URL,
|
|
||||||
txid: [UInt8],
|
txid: [UInt8],
|
||||||
index: Int,
|
index: Int,
|
||||||
script: [UInt8],
|
script: [UInt8],
|
||||||
value: Int64,
|
value: Int64,
|
||||||
height: BlockHeight,
|
height: BlockHeight
|
||||||
networkType: NetworkType
|
) async throws {
|
||||||
) async throws -> Bool {
|
|
||||||
let dbData = dbData.osStr()
|
|
||||||
|
|
||||||
guard zcashlc_put_utxo(
|
guard zcashlc_put_utxo(
|
||||||
dbData.0,
|
dbData.0,
|
||||||
dbData.1,
|
dbData.1,
|
||||||
|
@ -653,48 +481,51 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
) else {
|
) else {
|
||||||
throw lastError() ?? .genericError(message: "No error message available")
|
throw lastError() ?? .genericError(message: "No error message available")
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
static func validateCombinedChain(fsBlockDbRoot: URL, dbData: URL, networkType: NetworkType, limit: UInt32 = 0) async -> Int32 {
|
|
||||||
let dbCache = fsBlockDbRoot.osPathStr()
|
|
||||||
let dbData = dbData.osStr()
|
|
||||||
return zcashlc_validate_combined_chain(dbCache.0, dbCache.1, dbData.0, dbData.1, networkType.networkId, limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func rewindToHeight(dbData: URL, height: Int32, networkType: NetworkType) -> Bool {
|
|
||||||
let dbData = dbData.osStr()
|
|
||||||
return zcashlc_rewind_to_height(dbData.0, dbData.1, height, networkType.networkId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static func rewindCacheToHeight(
|
func validateCombinedChain(limit: UInt32 = 0) async throws {
|
||||||
fsBlockDbRoot: URL,
|
let result = zcashlc_validate_combined_chain(fsBlockDbRoot.0, fsBlockDbRoot.1, dbData.0, dbData.1, networkType.networkId, limit)
|
||||||
height: Int32
|
|
||||||
) -> Bool {
|
|
||||||
let fsBlockCache = fsBlockDbRoot.osPathStr()
|
|
||||||
|
|
||||||
return zcashlc_rewind_fs_block_cache_to_height(fsBlockCache.0, fsBlockCache.1, height)
|
switch result {
|
||||||
|
case -1:
|
||||||
|
return
|
||||||
|
case 0:
|
||||||
|
throw RustWeldingError.chainValidationFailed(message: getLastError())
|
||||||
|
default:
|
||||||
|
throw RustWeldingError.invalidChain(upperBound: result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func scanBlocks(fsBlockDbRoot: URL, dbData: URL, limit: UInt32 = 0, networkType: NetworkType) async -> Bool {
|
func rewindToHeight(height: Int32) async throws {
|
||||||
let dbCache = fsBlockDbRoot.osPathStr()
|
let result = zcashlc_rewind_to_height(dbData.0, dbData.1, height, networkType.networkId)
|
||||||
let dbData = dbData.osStr()
|
|
||||||
return zcashlc_scan_blocks(dbCache.0, dbCache.1, dbData.0, dbData.1, limit, networkType.networkId) != 0
|
guard result else {
|
||||||
|
throw lastError() ?? .genericError(message: "No error message available")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func shieldFunds(
|
func rewindCacheToHeight(height: Int32) async throws {
|
||||||
dbData: URL,
|
let result = zcashlc_rewind_fs_block_cache_to_height(fsBlockDbRoot.0, fsBlockDbRoot.1, height)
|
||||||
|
|
||||||
|
guard result else {
|
||||||
|
throw lastError() ?? .genericError(message: "No error message available")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanBlocks(limit: UInt32 = 0) async throws {
|
||||||
|
let result = zcashlc_scan_blocks(fsBlockDbRoot.0, fsBlockDbRoot.1, dbData.0, dbData.1, limit, networkType.networkId)
|
||||||
|
|
||||||
|
guard result != 0 else {
|
||||||
|
throw lastError() ?? .genericError(message: "No error message available")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func shieldFunds(
|
||||||
usk: UnifiedSpendingKey,
|
usk: UnifiedSpendingKey,
|
||||||
memo: MemoBytes?,
|
memo: MemoBytes?,
|
||||||
shieldingThreshold: Zatoshi,
|
shieldingThreshold: Zatoshi
|
||||||
spendParamsPath: String,
|
) async throws -> Int64 {
|
||||||
outputParamsPath: String,
|
let result = usk.bytes.withUnsafeBufferPointer { uskBuffer in
|
||||||
networkType: NetworkType
|
|
||||||
) async -> Int64 {
|
|
||||||
let dbData = dbData.osStr()
|
|
||||||
|
|
||||||
return usk.bytes.withUnsafeBufferPointer { uskBuffer in
|
|
||||||
zcashlc_shield_funds(
|
zcashlc_shield_funds(
|
||||||
dbData.0,
|
dbData.0,
|
||||||
dbData.1,
|
dbData.1,
|
||||||
|
@ -702,82 +533,36 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
UInt(usk.bytes.count),
|
UInt(usk.bytes.count),
|
||||||
memo?.bytes,
|
memo?.bytes,
|
||||||
UInt64(shieldingThreshold.amount),
|
UInt64(shieldingThreshold.amount),
|
||||||
spendParamsPath,
|
spendParamsPath.0,
|
||||||
UInt(spendParamsPath.lengthOfBytes(using: .utf8)),
|
spendParamsPath.1,
|
||||||
outputParamsPath,
|
outputParamsPath.0,
|
||||||
UInt(outputParamsPath.lengthOfBytes(using: .utf8)),
|
outputParamsPath.1,
|
||||||
networkType.networkId,
|
networkType.networkId,
|
||||||
minimumConfirmations,
|
minimumConfirmations,
|
||||||
useZIP317Fees
|
useZIP317Fees
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static func deriveUnifiedFullViewingKey(from spendingKey: UnifiedSpendingKey, networkType: NetworkType) throws -> UnifiedFullViewingKey {
|
|
||||||
let extfvk = try spendingKey.bytes.withUnsafeBufferPointer { uskBufferPtr -> UnsafeMutablePointer<CChar> in
|
|
||||||
guard let extfvk = zcashlc_spending_key_to_full_viewing_key(
|
|
||||||
uskBufferPtr.baseAddress,
|
|
||||||
UInt(spendingKey.bytes.count),
|
|
||||||
networkType.networkId
|
|
||||||
) else {
|
|
||||||
throw lastError() ?? .genericError(message: "No error message available")
|
|
||||||
}
|
|
||||||
|
|
||||||
return extfvk
|
guard result > 0 else {
|
||||||
|
throw lastError() ?? .genericError(message: "No error message available")
|
||||||
}
|
}
|
||||||
|
|
||||||
defer { zcashlc_string_free(extfvk) }
|
return result
|
||||||
|
|
||||||
guard let derived = String(validatingUTF8: extfvk) else {
|
|
||||||
throw RustWeldingError.unableToDeriveKeys
|
|
||||||
}
|
|
||||||
|
|
||||||
return UnifiedFullViewingKey(validatedEncoding: derived, account: spendingKey.account)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static func receiverTypecodesOnUnifiedAddress(_ address: String) throws -> [UInt32] {
|
nonisolated func consensusBranchIdFor(height: Int32) throws -> Int32 {
|
||||||
guard !address.containsCStringNullBytesBeforeStringEnding() else {
|
|
||||||
throw RustWeldingError.invalidInput(message: "`address` contains null bytes.")
|
|
||||||
}
|
|
||||||
|
|
||||||
var len = UInt(0)
|
|
||||||
|
|
||||||
guard let typecodesPointer = zcashlc_get_typecodes_for_unified_address_receivers(
|
|
||||||
[CChar](address.utf8CString),
|
|
||||||
&len
|
|
||||||
), len > 0
|
|
||||||
else {
|
|
||||||
throw RustWeldingError.malformedStringInput
|
|
||||||
}
|
|
||||||
|
|
||||||
var typecodes: [UInt32] = []
|
|
||||||
|
|
||||||
for typecodeIndex in 0 ..< Int(len) {
|
|
||||||
let pointer = typecodesPointer.advanced(by: typecodeIndex)
|
|
||||||
|
|
||||||
typecodes.append(pointer.pointee)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer {
|
|
||||||
zcashlc_free_typecodes(typecodesPointer, len)
|
|
||||||
}
|
|
||||||
|
|
||||||
return typecodes
|
|
||||||
}
|
|
||||||
|
|
||||||
static func consensusBranchIdFor(height: Int32, networkType: NetworkType) throws -> Int32 {
|
|
||||||
let branchId = zcashlc_branch_id_for_height(height, networkType.networkId)
|
let branchId = zcashlc_branch_id_for_height(height, networkType.networkId)
|
||||||
|
|
||||||
guard branchId != -1 else {
|
guard branchId != -1 else {
|
||||||
throw RustWeldingError.noConsensusBranchId(height: height)
|
throw RustWeldingError.noConsensusBranchId(height: height)
|
||||||
}
|
}
|
||||||
|
|
||||||
return branchId
|
return branchId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension ZcashRustBackend {
|
private extension ZcashRustBackend {
|
||||||
static func throwDataDbError(_ error: RustWeldingError) -> Error {
|
func throwDataDbError(_ error: RustWeldingError) -> Error {
|
||||||
if case RustWeldingError.genericError(let message) = error, message.contains("is not empty") {
|
if case RustWeldingError.genericError(let message) = error, message.contains("is not empty") {
|
||||||
return RustWeldingError.dataDbNotEmpty
|
return RustWeldingError.dataDbNotEmpty
|
||||||
}
|
}
|
||||||
|
@ -785,7 +570,7 @@ private extension ZcashRustBackend {
|
||||||
return RustWeldingError.dataDbInitFailed(message: error.localizedDescription)
|
return RustWeldingError.dataDbInitFailed(message: error.localizedDescription)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func throwBalanceError(account: Int32, _ error: RustWeldingError?, fallbackMessage: String) -> Error {
|
func throwBalanceError(account: Int32, _ error: RustWeldingError?, fallbackMessage: String) -> Error {
|
||||||
guard let balanceError = error else {
|
guard let balanceError = error else {
|
||||||
return RustWeldingError.genericError(message: fallbackMessage)
|
return RustWeldingError.genericError(message: fallbackMessage)
|
||||||
}
|
}
|
||||||
|
@ -865,6 +650,15 @@ extension RustWeldingError: LocalizedError {
|
||||||
return "`.unableToDeriveKeys` the requested keys could not be derived from the source provided"
|
return "`.unableToDeriveKeys` the requested keys could not be derived from the source provided"
|
||||||
case let .getBalanceError(account, error):
|
case let .getBalanceError(account, error):
|
||||||
return "`.getBalanceError` could not retrieve balance from account: \(account), error:\(error)"
|
return "`.getBalanceError` could not retrieve balance from account: \(account), error:\(error)"
|
||||||
|
case let .invalidChain(upperBound: upperBound):
|
||||||
|
return "`.validateCombinedChain` failed to validate chain. Upper bound: \(upperBound)."
|
||||||
|
case let .chainValidationFailed(message):
|
||||||
|
return """
|
||||||
|
`.validateCombinedChain` failed to validate chain because of error unrelated to chain validity. \
|
||||||
|
Message: \(String(describing: message))
|
||||||
|
"""
|
||||||
|
case .writeBlocksMetadataAllocationProblem:
|
||||||
|
return "`.writeBlocksMetadata` failed to allocate memory on Swift side necessary to write blocks metadata to db."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,13 @@ enum RustWeldingError: Error {
|
||||||
case getBalanceError(Int, Error)
|
case getBalanceError(Int, Error)
|
||||||
case invalidInput(message: String)
|
case invalidInput(message: String)
|
||||||
case invalidRewind(suggestedHeight: Int32)
|
case invalidRewind(suggestedHeight: Int32)
|
||||||
|
/// Thrown when `upperBound` if the combined chain is invalid. `upperBound` is the height of the highest invalid block (on the assumption that
|
||||||
|
/// the highest block in the cache database is correct).
|
||||||
|
case invalidChain(upperBound: Int32)
|
||||||
|
/// Thrown if there was an error during validation unrelated to chain validity.
|
||||||
|
case chainValidationFailed(message: String?)
|
||||||
|
/// Thrown if there was problem with memory allocation on the Swift side while trying to write blocks metadata to DB.
|
||||||
|
case writeBlocksMetadataAllocationProblem
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ZcashRustBackendWeldingConstants {
|
enum ZcashRustBackendWeldingConstants {
|
||||||
|
@ -31,6 +38,7 @@ public enum DbInitResult {
|
||||||
case seedRequired
|
case seedRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sourcery: mockActor
|
||||||
protocol ZcashRustBackendWelding {
|
protocol ZcashRustBackendWelding {
|
||||||
/// Adds the next available account-level spend authority, given the current set of [ZIP 316]
|
/// Adds the next available account-level spend authority, given the current set of [ZIP 316]
|
||||||
/// account identifiers known, to the wallet database.
|
/// account identifiers known, to the wallet database.
|
||||||
|
@ -46,83 +54,34 @@ protocol ZcashRustBackendWelding {
|
||||||
/// By convention, wallets should only allow a new account to be generated after funds
|
/// By convention, wallets should only allow a new account to be generated after funds
|
||||||
/// have been received by the currently-available account (in order to enable
|
/// have been received by the currently-available account (in order to enable
|
||||||
/// automated account recovery).
|
/// automated account recovery).
|
||||||
/// - parameter dbData: location of the data db
|
|
||||||
/// - parameter seed: byte array of the zip32 seed
|
/// - parameter seed: byte array of the zip32 seed
|
||||||
/// - parameter networkType: network type of this key
|
|
||||||
/// - Returns: The `UnifiedSpendingKey` structs for the number of accounts created
|
/// - Returns: The `UnifiedSpendingKey` structs for the number of accounts created
|
||||||
///
|
func createAccount(seed: [UInt8]) async throws -> UnifiedSpendingKey
|
||||||
static func createAccount(
|
|
||||||
dbData: URL,
|
|
||||||
seed: [UInt8],
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws -> UnifiedSpendingKey
|
|
||||||
|
|
||||||
/// Creates a transaction to the given address from the given account
|
/// Creates a transaction to the given address from the given account
|
||||||
/// - Parameter dbData: URL for the Data DB
|
|
||||||
/// - Parameter usk: `UnifiedSpendingKey` for the account that controls the funds to be spent.
|
/// - Parameter usk: `UnifiedSpendingKey` for the account that controls the funds to be spent.
|
||||||
/// - Parameter to: recipient address
|
/// - Parameter to: recipient address
|
||||||
/// - Parameter value: transaction amount in Zatoshi
|
/// - Parameter value: transaction amount in Zatoshi
|
||||||
/// - Parameter memo: the `MemoBytes` for this transaction. pass `nil` when sending to transparent receivers
|
/// - Parameter memo: the `MemoBytes` for this transaction. pass `nil` when sending to transparent receivers
|
||||||
/// - Parameter spendParamsPath: path escaped String for the filesystem locations where the spend parameters are located
|
func createToAddress(
|
||||||
/// - Parameter outputParamsPath: path escaped String for the filesystem locations where the output parameters are located
|
|
||||||
/// - Parameter networkType: network type of this key
|
|
||||||
// swiftlint:disable:next function_parameter_count
|
|
||||||
static func createToAddress(
|
|
||||||
dbData: URL,
|
|
||||||
usk: UnifiedSpendingKey,
|
usk: UnifiedSpendingKey,
|
||||||
to address: String,
|
to address: String,
|
||||||
value: Int64,
|
value: Int64,
|
||||||
memo: MemoBytes?,
|
memo: MemoBytes?
|
||||||
spendParamsPath: String,
|
|
||||||
outputParamsPath: String,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async -> Int64 // swiftlint:disable function_parameter_count
|
|
||||||
|
|
||||||
/// Scans a transaction for any information that can be decrypted by the accounts in the
|
|
||||||
/// wallet, and saves it to the wallet.
|
|
||||||
/// - parameter dbData: location of the data db file
|
|
||||||
/// - parameter tx: the transaction to decrypt
|
|
||||||
/// - parameter minedHeight: height on which this transaction was mined. this is used to fetch the consensus branch ID.
|
|
||||||
/// - parameter networkType: network type of this key
|
|
||||||
/// returns false if fails to decrypt.
|
|
||||||
static func decryptAndStoreTransaction(
|
|
||||||
dbData: URL,
|
|
||||||
txBytes: [UInt8],
|
|
||||||
minedHeight: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async -> Bool
|
|
||||||
|
|
||||||
/// Derives and returns a unified spending key from the given seed for the given account ID.
|
|
||||||
/// Returns the binary encoding of the spending key. The caller should manage the memory of (and store, if necessary) the returned spending key in a secure fashion.
|
|
||||||
/// - Parameter seed: a Byte Array with the seed
|
|
||||||
/// - Parameter accountIndex:account index that the key can spend from
|
|
||||||
/// - Parameter networkType: network type of this key
|
|
||||||
/// - Throws `.unableToDerive` when there's an error
|
|
||||||
static func deriveUnifiedSpendingKey(
|
|
||||||
from seed: [UInt8],
|
|
||||||
accountIndex: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) throws -> UnifiedSpendingKey
|
|
||||||
|
|
||||||
/// get the (unverified) balance from the given account
|
|
||||||
/// - parameter dbData: location of the data db
|
|
||||||
/// - parameter account: index of the given account
|
|
||||||
/// - parameter networkType: network type of this key
|
|
||||||
static func getBalance(
|
|
||||||
dbData: URL,
|
|
||||||
account: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws -> Int64
|
) async throws -> Int64
|
||||||
|
|
||||||
/// Returns the most-recently-generated unified payment address for the specified account.
|
/// Scans a transaction for any information that can be decrypted by the accounts in the wallet, and saves it to the wallet.
|
||||||
/// - parameter dbData: location of the data db
|
/// - parameter tx: the transaction to decrypt
|
||||||
|
/// - parameter minedHeight: height on which this transaction was mined. this is used to fetch the consensus branch ID.
|
||||||
|
func decryptAndStoreTransaction(txBytes: [UInt8], minedHeight: Int32) async throws
|
||||||
|
|
||||||
|
/// Get the (unverified) balance from the given account.
|
||||||
/// - parameter account: index of the given account
|
/// - parameter account: index of the given account
|
||||||
/// - parameter networkType: network type of this key
|
func getBalance(account: Int32) async throws -> Int64
|
||||||
static func getCurrentAddress(
|
|
||||||
dbData: URL,
|
/// Returns the most-recently-generated unified payment address for the specified account.
|
||||||
account: Int32,
|
/// - parameter account: index of the given account
|
||||||
networkType: NetworkType
|
func getCurrentAddress(account: Int32) async throws -> UnifiedAddress
|
||||||
) async throws -> UnifiedAddress
|
|
||||||
|
|
||||||
/// Wallets might need to be rewound because of a reorg, or by user request.
|
/// Wallets might need to be rewound because of a reorg, or by user request.
|
||||||
/// There are times where the wallet could get out of sync for many reasons and
|
/// There are times where the wallet could get out of sync for many reasons and
|
||||||
|
@ -131,195 +90,64 @@ protocol ZcashRustBackendWelding {
|
||||||
/// of sapling witnesses older than 100 blocks. So in order to reconstruct the witness
|
/// of sapling witnesses older than 100 blocks. So in order to reconstruct the witness
|
||||||
/// tree that allows to spend notes from the given wallet the rewind can't be more than
|
/// tree that allows to spend notes from the given wallet the rewind can't be more than
|
||||||
/// 100 blocks or back to the oldest unspent note that this wallet contains.
|
/// 100 blocks or back to the oldest unspent note that this wallet contains.
|
||||||
/// - parameter dbData: location of the data db file
|
|
||||||
/// - parameter height: height you would like to rewind to.
|
/// - parameter height: height you would like to rewind to.
|
||||||
/// - parameter networkType: network type of this key]
|
|
||||||
/// - Returns: the blockheight of the nearest rewind height.
|
/// - Returns: the blockheight of the nearest rewind height.
|
||||||
///
|
func getNearestRewindHeight(height: Int32) async throws -> Int32
|
||||||
static func getNearestRewindHeight(
|
|
||||||
dbData: URL,
|
|
||||||
height: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async -> Int32
|
|
||||||
|
|
||||||
/// Returns a newly-generated unified payment address for the specified account, with the next available diversifier.
|
/// Returns a newly-generated unified payment address for the specified account, with the next available diversifier.
|
||||||
/// - parameter dbData: location of the data db
|
|
||||||
/// - parameter account: index of the given account
|
/// - parameter account: index of the given account
|
||||||
/// - parameter networkType: network type of this key
|
func getNextAvailableAddress(account: Int32) async throws -> UnifiedAddress
|
||||||
static func getNextAvailableAddress(
|
|
||||||
dbData: URL,
|
|
||||||
account: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws -> UnifiedAddress
|
|
||||||
|
|
||||||
/// get received memo from note
|
/// Get received memo from note.
|
||||||
/// - parameter dbData: location of the data db file
|
|
||||||
/// - parameter idNote: note_id of note where the memo is located
|
/// - parameter idNote: note_id of note where the memo is located
|
||||||
/// - parameter networkType: network type of this key
|
func getReceivedMemo(idNote: Int64) async -> Memo?
|
||||||
static func getReceivedMemo(
|
|
||||||
dbData: URL,
|
|
||||||
idNote: Int64,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async -> Memo?
|
|
||||||
|
|
||||||
/// Returns the Sapling receiver within the given Unified Address, if any.
|
/// Get sent memo from note.
|
||||||
/// - Parameter uAddr: a `UnifiedAddress`
|
|
||||||
/// - Returns a `SaplingAddress` if any
|
|
||||||
/// - Throws `receiverNotFound` when the receiver is not found. `invalidUnifiedAddress` if the UA provided is not valid
|
|
||||||
static func getSaplingReceiver(for uAddr: UnifiedAddress) throws -> SaplingAddress
|
|
||||||
|
|
||||||
/// get sent memo from note
|
|
||||||
/// - parameter dbData: location of the data db file
|
|
||||||
/// - parameter idNote: note_id of note where the memo is located
|
/// - parameter idNote: note_id of note where the memo is located
|
||||||
/// - parameter networkType: network type of this key
|
|
||||||
/// - Returns: a `Memo` if any
|
/// - Returns: a `Memo` if any
|
||||||
static func getSentMemo(
|
func getSentMemo(idNote: Int64) async -> Memo?
|
||||||
dbData: URL,
|
|
||||||
idNote: Int64,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async -> Memo?
|
|
||||||
|
|
||||||
/// Get the verified cached transparent balance for the given address
|
/// Get the verified cached transparent balance for the given address
|
||||||
/// - parameter dbData: location of the data db file
|
|
||||||
/// - parameter account; the account index to query
|
/// - parameter account; the account index to query
|
||||||
/// - parameter networkType: network type of this key
|
func getTransparentBalance(account: Int32) async throws -> Int64
|
||||||
static func getTransparentBalance(
|
|
||||||
dbData: URL,
|
|
||||||
account: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws -> Int64
|
|
||||||
|
|
||||||
/// Returns the transparent receiver within the given Unified Address, if any.
|
/// Initialize the accounts table from a set of unified full viewing keys.
|
||||||
/// - parameter uAddr: a `UnifiedAddress`
|
/// - Note: this function should only be used when restoring an existing seed phrase. when creating a new wallet, use `createAccount()` instead.
|
||||||
/// - Returns a `TransparentAddress` if any
|
|
||||||
/// - Throws `receiverNotFound` when the receiver is not found. `invalidUnifiedAddress` if the UA provided is not valid
|
|
||||||
static func getTransparentReceiver(for uAddr: UnifiedAddress) throws -> TransparentAddress
|
|
||||||
|
|
||||||
/// gets the latest error if available. Clear the existing error
|
|
||||||
/// - Returns a `RustWeldingError` if exists
|
|
||||||
static func lastError() -> RustWeldingError?
|
|
||||||
|
|
||||||
/// gets the latest error message from librustzcash. Does not clear existing error
|
|
||||||
static func getLastError() -> String?
|
|
||||||
|
|
||||||
/// initialize the accounts table from a set of unified full viewing keys
|
|
||||||
/// - Note: this function should only be used when restoring an existing seed phrase.
|
|
||||||
/// when creating a new wallet, use `createAccount()` instead
|
|
||||||
/// - Parameter dbData: location of the data db
|
|
||||||
/// - Parameter ufvks: an array of UnifiedFullViewingKeys
|
/// - Parameter ufvks: an array of UnifiedFullViewingKeys
|
||||||
/// - Parameter networkType: network type of this key
|
func initAccountsTable(ufvks: [UnifiedFullViewingKey]) async throws
|
||||||
static func initAccountsTable(
|
|
||||||
dbData: URL,
|
|
||||||
ufvks: [UnifiedFullViewingKey],
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws
|
|
||||||
|
|
||||||
/// initializes the data db. This will performs any migrations needed on the sqlite file
|
/// Initializes the data db. This will performs any migrations needed on the sqlite file
|
||||||
/// provided. Some migrations might need that callers provide the seed bytes.
|
/// provided. Some migrations might need that callers provide the seed bytes.
|
||||||
/// - Parameter dbData: location of the data db sql file
|
|
||||||
/// - Parameter seed: ZIP-32 compliant seed bytes for this wallet
|
/// - Parameter seed: ZIP-32 compliant seed bytes for this wallet
|
||||||
/// - Parameter networkType: network type of this key
|
|
||||||
/// - Returns: `DbInitResult.success` if the dataDb was initialized successfully
|
/// - Returns: `DbInitResult.success` if the dataDb was initialized successfully
|
||||||
/// or `DbInitResult.seedRequired` if the operation requires the seed to be passed
|
/// or `DbInitResult.seedRequired` if the operation requires the seed to be passed
|
||||||
/// in order to be completed successfully.
|
/// in order to be completed successfully.
|
||||||
static func initDataDb(
|
func initDataDb(seed: [UInt8]?) async throws -> DbInitResult
|
||||||
dbData: URL,
|
|
||||||
seed: [UInt8]?,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws -> DbInitResult
|
|
||||||
|
|
||||||
/// Returns the network and address type for the given Zcash address string,
|
/// Initialize the blocks table from a given checkpoint (heigh, hash, time, saplingTree and networkType).
|
||||||
/// if the string represents a valid Zcash address.
|
|
||||||
static func getAddressMetadata(_ address: String) -> AddressMetadata?
|
|
||||||
|
|
||||||
/// Validates the if the given string is a valid Sapling Address
|
|
||||||
/// - Parameter address: UTF-8 encoded String to validate
|
|
||||||
/// - Parameter networkType: network type of this key
|
|
||||||
/// - Returns: true when the address is valid. Returns false in any other case
|
|
||||||
/// - Throws: Error when the provided address belongs to another network
|
|
||||||
static func isValidSaplingAddress(_ address: String, networkType: NetworkType) -> Bool
|
|
||||||
|
|
||||||
/// Validates the if the given string is a valid Sapling Extended Full Viewing Key
|
|
||||||
/// - Parameter key: UTF-8 encoded String to validate
|
|
||||||
/// - Parameter networkType: network type of this key
|
|
||||||
/// - Returns: `true` when the Sapling Extended Full Viewing Key is valid. `false` in any other case
|
|
||||||
/// - Throws: Error when there's another problem not related to validity of the string in question
|
|
||||||
static func isValidSaplingExtendedFullViewingKey(_ key: String, networkType: NetworkType) -> Bool
|
|
||||||
|
|
||||||
/// Validates the if the given string is a valid Sapling Extended Spending Key
|
|
||||||
/// - Returns: `true` when the Sapling Extended Spending Key is valid, false in any other case.
|
|
||||||
/// - Throws: Error when the key is semantically valid but it belongs to another network
|
|
||||||
/// - parameter key: String encoded Extended Spending Key
|
|
||||||
/// - parameter networkType: `NetworkType` signaling testnet or mainnet
|
|
||||||
static func isValidSaplingExtendedSpendingKey(_ key: String, networkType: NetworkType) -> Bool
|
|
||||||
|
|
||||||
/// Validates the if the given string is a valid Transparent Address
|
|
||||||
/// - Parameter address: UTF-8 encoded String to validate
|
|
||||||
/// - Parameter networkType: network type of this key
|
|
||||||
/// - Returns: true when the address is valid and transparent. false in any other case
|
|
||||||
/// - Throws: Error when the provided address belongs to another network
|
|
||||||
static func isValidTransparentAddress(_ address: String, networkType: NetworkType) -> Bool
|
|
||||||
|
|
||||||
/// validates whether a string encoded address is a valid Unified Address.
|
|
||||||
/// - Parameter address: UTF-8 encoded String to validate
|
|
||||||
/// - Parameter networkType: network type of this key
|
|
||||||
/// - Returns: true when the address is valid and transparent. false in any other case
|
|
||||||
/// - Throws: Error when the provided address belongs to another network
|
|
||||||
static func isValidUnifiedAddress(_ address: String, networkType: NetworkType) -> Bool
|
|
||||||
|
|
||||||
/// verifies that the given string-encoded `UnifiedFullViewingKey` is valid.
|
|
||||||
/// - Parameter ufvk: UTF-8 encoded String to validate
|
|
||||||
/// - Parameter networkType: network type of this key
|
|
||||||
/// - Returns: true when the encoded string is a valid UFVK. false in any other case
|
|
||||||
/// - Throws: Error when there's another problem not related to validity of the string in question
|
|
||||||
static func isValidUnifiedFullViewingKey(_ ufvk: String, networkType: NetworkType) -> Bool
|
|
||||||
|
|
||||||
/// initialize the blocks table from a given checkpoint (heigh, hash, time, saplingTree and networkType)
|
|
||||||
/// - parameter dbData: location of the data db
|
|
||||||
/// - parameter height: represents the block height of the given checkpoint
|
/// - parameter height: represents the block height of the given checkpoint
|
||||||
/// - parameter hash: hash of the merkle tree
|
/// - parameter hash: hash of the merkle tree
|
||||||
/// - parameter time: in milliseconds from reference
|
/// - parameter time: in milliseconds from reference
|
||||||
/// - parameter saplingTree: hash of the sapling tree
|
/// - parameter saplingTree: hash of the sapling tree
|
||||||
/// - parameter networkType: `NetworkType` signaling testnet or mainnet
|
func initBlocksTable(
|
||||||
static func initBlocksTable(
|
|
||||||
dbData: URL,
|
|
||||||
height: Int32,
|
height: Int32,
|
||||||
hash: String,
|
hash: String,
|
||||||
time: UInt32,
|
time: UInt32,
|
||||||
saplingTree: String,
|
saplingTree: String
|
||||||
networkType: NetworkType
|
) async throws
|
||||||
) async throws // swiftlint:disable function_parameter_count
|
|
||||||
|
|
||||||
/// Returns a list of the transparent receivers for the diversified unified addresses that have
|
/// Returns a list of the transparent receivers for the diversified unified addresses that have
|
||||||
/// been allocated for the provided account.
|
/// been allocated for the provided account.
|
||||||
/// - parameter dbData: location of the data db
|
|
||||||
/// - parameter account: index of the given account
|
/// - parameter account: index of the given account
|
||||||
/// - parameter networkType: the network type
|
func listTransparentReceivers(account: Int32) async throws -> [TransparentAddress]
|
||||||
static func listTransparentReceivers(
|
|
||||||
dbData: URL,
|
|
||||||
account: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws -> [TransparentAddress]
|
|
||||||
|
|
||||||
/// get the verified balance from the given account
|
/// Get the verified balance from the given account
|
||||||
/// - parameter dbData: location of the data db
|
|
||||||
/// - parameter account: index of the given account
|
/// - parameter account: index of the given account
|
||||||
/// - parameter networkType: the network type
|
func getVerifiedBalance(account: Int32) async throws -> Int64
|
||||||
static func getVerifiedBalance(
|
|
||||||
dbData: URL,
|
|
||||||
account: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws -> Int64
|
|
||||||
|
|
||||||
/// Get the verified cached transparent balance for the given account
|
/// Get the verified cached transparent balance for the given account
|
||||||
/// - parameter dbData: location of the data db
|
|
||||||
/// - parameter account: account index to query the balance for.
|
/// - parameter account: account index to query the balance for.
|
||||||
/// - parameter networkType: the network type
|
func getVerifiedTransparentBalance(account: Int32) async throws -> Int64
|
||||||
static func getVerifiedTransparentBalance(
|
|
||||||
dbData: URL,
|
|
||||||
account: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws -> Int64
|
|
||||||
|
|
||||||
/// Checks that the scanned blocks in the data database, when combined with the recent
|
/// Checks that the scanned blocks in the data database, when combined with the recent
|
||||||
/// `CompactBlock`s in the cache database, form a valid chain.
|
/// `CompactBlock`s in the cache database, form a valid chain.
|
||||||
|
@ -333,39 +161,22 @@ protocol ZcashRustBackendWelding {
|
||||||
/// - parameter dbData: location of the data db file
|
/// - parameter dbData: location of the data db file
|
||||||
/// - parameter networkType: the network type
|
/// - parameter networkType: the network type
|
||||||
/// - parameter limit: a limit to validate a fixed number of blocks instead of the whole cache.
|
/// - parameter limit: a limit to validate a fixed number of blocks instead of the whole cache.
|
||||||
/// - Returns:
|
/// - Throws:
|
||||||
/// - `-1` if the combined chain is valid.
|
/// - `RustWeldingError.chainValidationFailed` if there was an error during validation unrelated to chain validity.
|
||||||
/// - `upper_bound` if the combined chain is invalid.
|
/// - `RustWeldingError.invalidChain(upperBound)` if the combined chain is invalid. `upperBound` is the height of the highest invalid block
|
||||||
/// - `upper_bound` is the height of the highest invalid block (on the assumption that the highest block in the cache database is correct).
|
/// (on the assumption that the highest block in the cache database is correct).
|
||||||
/// - `0` if there was an error during validation unrelated to chain validity.
|
///
|
||||||
/// - Important: This function does not mutate either of the databases.
|
/// - Important: This function does not mutate either of the databases.
|
||||||
static func validateCombinedChain(
|
func validateCombinedChain(limit: UInt32) async throws
|
||||||
fsBlockDbRoot: URL,
|
|
||||||
dbData: URL,
|
|
||||||
networkType: NetworkType,
|
|
||||||
limit: UInt32
|
|
||||||
) async -> Int32
|
|
||||||
|
|
||||||
/// Resets the state of the database to only contain block and transaction information up to the given height. clears up all derived data as well
|
/// Resets the state of the database to only contain block and transaction information up to the given height. clears up all derived data as well
|
||||||
/// - parameter dbData: `URL` pointing to the filesystem root directory where the fsBlock cache is.
|
|
||||||
/// this directory is expected to contain a `/blocks` sub-directory with the blocks stored in the convened filename
|
|
||||||
/// format `{height}-{hash}-block`. This directory has must be granted both write and read permissions.
|
|
||||||
/// - parameter height: height to rewind to.
|
/// - parameter height: height to rewind to.
|
||||||
static func rewindToHeight(
|
func rewindToHeight(height: Int32) async throws
|
||||||
dbData: URL,
|
|
||||||
height: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async -> Bool
|
|
||||||
|
|
||||||
/// Resets the state of the FsBlock database to only contain block and transaction information up to the given height.
|
/// Resets the state of the FsBlock database to only contain block and transaction information up to the given height.
|
||||||
/// - Note: this does not delete the files. Only rolls back the database.
|
/// - Note: this does not delete the files. Only rolls back the database.
|
||||||
/// - parameter fsBlockDbRoot: location of the data db file
|
/// - parameter height: height to rewind to. DON'T PASS ARBITRARY HEIGHT. Use `getNearestRewindHeight` when unsure
|
||||||
/// - parameter height: height to rewind to. DON'T PASS ARBITRARY HEIGHT. Use getNearestRewindHeight when unsure
|
func rewindCacheToHeight(height: Int32) async throws
|
||||||
/// - parameter networkType: the network type
|
|
||||||
static func rewindCacheToHeight(
|
|
||||||
fsBlockDbRoot: URL,
|
|
||||||
height: Int32
|
|
||||||
) async -> Bool
|
|
||||||
|
|
||||||
/// Scans new blocks added to the cache for any transactions received by the tracked
|
/// Scans new blocks added to the cache for any transactions received by the tracked
|
||||||
/// accounts.
|
/// accounts.
|
||||||
|
@ -379,101 +190,48 @@ protocol ZcashRustBackendWelding {
|
||||||
/// Scanned blocks are required to be height-sequential. If a block is missing from the
|
/// Scanned blocks are required to be height-sequential. If a block is missing from the
|
||||||
/// cache, an error will be signalled.
|
/// cache, an error will be signalled.
|
||||||
///
|
///
|
||||||
/// - parameter fsBlockDbRoot: `URL` pointing to the filesystem root directory where the fsBlock cache is.
|
|
||||||
/// this directory is expected to contain a `/blocks` sub-directory with the blocks stored in the convened filename
|
|
||||||
/// format `{height}-{hash}-block`. This directory has must be granted both write and read permissions.
|
|
||||||
/// - parameter dbData: location of the data db sqlite file
|
|
||||||
/// - parameter limit: scan up to limit blocks. pass 0 to set no limit.
|
/// - parameter limit: scan up to limit blocks. pass 0 to set no limit.
|
||||||
/// - parameter networkType: the network type
|
func scanBlocks(limit: UInt32) async throws
|
||||||
/// returns false if fails to scan.
|
|
||||||
static func scanBlocks(
|
|
||||||
fsBlockDbRoot: URL,
|
|
||||||
dbData: URL,
|
|
||||||
limit: UInt32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async -> Bool
|
|
||||||
|
|
||||||
/// Upserts a UTXO into the data db database
|
/// Upserts a UTXO into the data db database
|
||||||
/// - parameter dbData: location of the data db file
|
|
||||||
/// - parameter txid: the txid bytes for the UTXO
|
/// - parameter txid: the txid bytes for the UTXO
|
||||||
/// - parameter index: the index of the UTXO
|
/// - parameter index: the index of the UTXO
|
||||||
/// - parameter script: the script of the UTXO
|
/// - parameter script: the script of the UTXO
|
||||||
/// - parameter value: the value of the UTXO
|
/// - parameter value: the value of the UTXO
|
||||||
/// - parameter height: the mined height for the UTXO
|
/// - parameter height: the mined height for the UTXO
|
||||||
/// - parameter networkType: the network type
|
func putUnspentTransparentOutput(
|
||||||
/// - Returns: true if the operation succeded or false otherwise
|
|
||||||
static func putUnspentTransparentOutput(
|
|
||||||
dbData: URL,
|
|
||||||
txid: [UInt8],
|
txid: [UInt8],
|
||||||
index: Int,
|
index: Int,
|
||||||
script: [UInt8],
|
script: [UInt8],
|
||||||
value: Int64,
|
value: Int64,
|
||||||
height: BlockHeight,
|
height: BlockHeight
|
||||||
networkType: NetworkType
|
) async throws
|
||||||
) async throws -> Bool
|
|
||||||
|
|
||||||
/// Creates a transaction to shield all found UTXOs in data db for the account the provided `UnifiedSpendingKey` has spend authority for.
|
/// Creates a transaction to shield all found UTXOs in data db for the account the provided `UnifiedSpendingKey` has spend authority for.
|
||||||
/// - Parameter dbData: URL for the Data DB
|
|
||||||
/// - Parameter usk: `UnifiedSpendingKey` that spend transparent funds and where the funds will be shielded to.
|
/// - Parameter usk: `UnifiedSpendingKey` that spend transparent funds and where the funds will be shielded to.
|
||||||
/// - Parameter memo: the `Memo` for this transaction
|
/// - Parameter memo: the `Memo` for this transaction
|
||||||
/// - Parameter spendParamsPath: path escaped String for the filesystem locations where the spend parameters are located
|
func shieldFunds(
|
||||||
/// - Parameter outputParamsPath: path escaped String for the filesystem locations where the output parameters are located
|
|
||||||
/// - Parameter networkType: the network type
|
|
||||||
static func shieldFunds(
|
|
||||||
dbData: URL,
|
|
||||||
usk: UnifiedSpendingKey,
|
usk: UnifiedSpendingKey,
|
||||||
memo: MemoBytes?,
|
memo: MemoBytes?,
|
||||||
shieldingThreshold: Zatoshi,
|
shieldingThreshold: Zatoshi
|
||||||
spendParamsPath: String,
|
) async throws -> Int64
|
||||||
outputParamsPath: String,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async -> Int64
|
|
||||||
|
|
||||||
/// Obtains the available receiver typecodes for the given String encoded Unified Address
|
|
||||||
/// - Parameter address: public key represented as a String
|
|
||||||
/// - Returns the `[UInt32]` that compose the given UA
|
|
||||||
/// - Throws `RustWeldingError.invalidInput(message: String)` when the UA is either invalid or malformed
|
|
||||||
static func receiverTypecodesOnUnifiedAddress(_ address: String) throws -> [UInt32]
|
|
||||||
|
|
||||||
/// Gets the consensus branch id for the given height
|
/// Gets the consensus branch id for the given height
|
||||||
/// - Parameter height: the height you what to know the branch id for
|
/// - Parameter height: the height you what to know the branch id for
|
||||||
/// - Parameter networkType: the network type
|
func consensusBranchIdFor(height: Int32) throws -> Int32
|
||||||
static func consensusBranchIdFor(
|
|
||||||
height: Int32,
|
|
||||||
networkType: NetworkType
|
|
||||||
) throws -> Int32
|
|
||||||
|
|
||||||
/// Derives a `UnifiedFullViewingKey` from a `UnifiedSpendingKey`
|
/// Initializes Filesystem based block cache
|
||||||
/// - Parameter spendingKey: the `UnifiedSpendingKey` to derive from
|
|
||||||
/// - Parameter networkType: the network type
|
|
||||||
/// - Throws: `RustWeldingError.unableToDeriveKeys` if the SDK couldn't derive the UFVK.
|
|
||||||
/// - Returns: the derived `UnifiedFullViewingKey`
|
|
||||||
static func deriveUnifiedFullViewingKey(
|
|
||||||
from spendingKey: UnifiedSpendingKey,
|
|
||||||
networkType: NetworkType
|
|
||||||
) throws -> UnifiedFullViewingKey
|
|
||||||
|
|
||||||
/// initializes Filesystem based block cache
|
|
||||||
/// - Parameter fsBlockDbRoot: `URL` pointing to the filesystem root directory where the fsBlock cache is.
|
|
||||||
/// this directory is expected to contain a `/blocks` sub-directory with the blocks stored in the convened filename
|
|
||||||
/// format `{height}-{hash}-block`. This directory has must be granted both write and read permissions.
|
|
||||||
/// - returns `true` when successful, `false` when fails but no throwing information was found
|
|
||||||
/// - throws `RustWeldingError` when fails to initialize
|
/// - throws `RustWeldingError` when fails to initialize
|
||||||
static func initBlockMetadataDb(fsBlockDbRoot: URL) async throws -> Bool
|
func initBlockMetadataDb() async throws
|
||||||
|
|
||||||
/// Write compact block metadata to a database known to the Rust layer
|
/// Write compact block metadata to a database known to the Rust layer
|
||||||
/// - Parameter fsBlockDbRoot: `URL` pointing to the filesystem root directory where the fsBlock cache is.
|
/// - Parameter blocks: The `ZcashCompactBlock`s that are going to be marked as stored by the metadata Db.
|
||||||
/// this directory is expected to contain a `/blocks` sub-directory with the blocks stored in the convened filename
|
func writeBlocksMetadata(blocks: [ZcashCompactBlock]) async throws
|
||||||
/// format `{height}-{hash}-block`. This directory has must be granted both write and read permissions.
|
|
||||||
/// - Parameter blocks: The `ZcashCompactBlock`s that are going to be marked as stored by the
|
|
||||||
/// metadata Db.
|
|
||||||
/// - Returns `true` if the operation was successful, `false` otherwise.
|
|
||||||
static func writeBlocksMetadata(fsBlockDbRoot: URL, blocks: [ZcashCompactBlock]) async throws -> Bool
|
|
||||||
|
|
||||||
/// Gets the latest block height stored in the filesystem based cache.
|
/// Gets the latest block height stored in the filesystem based cache.
|
||||||
/// - Parameter fsBlockDbRoot: `URL` pointing to the filesystem root directory where the fsBlock cache is.
|
/// - Parameter fsBlockDbRoot: `URL` pointing to the filesystem root directory where the fsBlock cache is.
|
||||||
/// this directory is expected to contain a `/blocks` sub-directory with the blocks stored in the convened filename
|
/// this directory is expected to contain a `/blocks` sub-directory with the blocks stored in the convened filename
|
||||||
/// format `{height}-{hash}-block`. This directory has must be granted both write and read permissions.
|
/// format `{height}-{hash}-block`. This directory has must be granted both write and read permissions.
|
||||||
/// - Returns `BlockHeight` of the latest cached block or `.empty` if no blocks are stored.
|
/// - Returns `BlockHeight` of the latest cached block or `.empty` if no blocks are stored.
|
||||||
static func latestCachedBlockHeight(fsBlockDbRoot: URL) async -> BlockHeight
|
func latestCachedBlockHeight() async -> BlockHeight
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,24 +230,34 @@ public protocol Synchronizer: AnyObject {
|
||||||
func paginatedTransactions(of kind: TransactionKind) -> PaginatedTransactionRepository
|
func paginatedTransactions(of kind: TransactionKind) -> PaginatedTransactionRepository
|
||||||
|
|
||||||
/// Get all memos for `transaction`.
|
/// Get all memos for `transaction`.
|
||||||
|
///
|
||||||
|
// sourcery: mockedName="getMemosForClearedTransaction"
|
||||||
func getMemos(for transaction: ZcashTransaction.Overview) async throws -> [Memo]
|
func getMemos(for transaction: ZcashTransaction.Overview) async throws -> [Memo]
|
||||||
|
|
||||||
/// Get all memos for `receivedTransaction`.
|
/// Get all memos for `receivedTransaction`.
|
||||||
|
///
|
||||||
|
// sourcery: mockedName="getMemosForReceivedTransaction"
|
||||||
func getMemos(for receivedTransaction: ZcashTransaction.Received) async throws -> [Memo]
|
func getMemos(for receivedTransaction: ZcashTransaction.Received) async throws -> [Memo]
|
||||||
|
|
||||||
/// Get all memos for `sentTransaction`.
|
/// Get all memos for `sentTransaction`.
|
||||||
|
///
|
||||||
|
// sourcery: mockedName="getMemosForSentTransaction"
|
||||||
func getMemos(for sentTransaction: ZcashTransaction.Sent) async throws -> [Memo]
|
func getMemos(for sentTransaction: ZcashTransaction.Sent) async throws -> [Memo]
|
||||||
|
|
||||||
/// Attempt to get recipients from a Transaction Overview.
|
/// Attempt to get recipients from a Transaction Overview.
|
||||||
/// - parameter transaction: A transaction overview
|
/// - parameter transaction: A transaction overview
|
||||||
/// - returns the recipients or an empty array if no recipients are found on this transaction because it's not an outgoing
|
/// - returns the recipients or an empty array if no recipients are found on this transaction because it's not an outgoing
|
||||||
/// transaction
|
/// transaction
|
||||||
|
///
|
||||||
|
// sourcery: mockedName="getRecipientsForClearedTransaction"
|
||||||
func getRecipients(for transaction: ZcashTransaction.Overview) async -> [TransactionRecipient]
|
func getRecipients(for transaction: ZcashTransaction.Overview) async -> [TransactionRecipient]
|
||||||
|
|
||||||
/// Get the recipients for the given a sent transaction
|
/// Get the recipients for the given a sent transaction
|
||||||
/// - parameter transaction: A transaction overview
|
/// - parameter transaction: A transaction overview
|
||||||
/// - returns the recipients or an empty array if no recipients are found on this transaction because it's not an outgoing
|
/// - returns the recipients or an empty array if no recipients are found on this transaction because it's not an outgoing
|
||||||
/// transaction
|
/// transaction
|
||||||
|
///
|
||||||
|
// sourcery: mockedName="getRecipientsForSentTransaction"
|
||||||
func getRecipients(for transaction: ZcashTransaction.Sent) async -> [TransactionRecipient]
|
func getRecipients(for transaction: ZcashTransaction.Sent) async -> [TransactionRecipient]
|
||||||
|
|
||||||
/// Returns a list of confirmed transactions that preceed the given transaction with a limit count.
|
/// Returns a list of confirmed transactions that preceed the given transaction with a limit count.
|
||||||
|
|
|
@ -37,37 +37,37 @@ extension ClosureSDKSynchronizer: ClosureSynchronizer {
|
||||||
walletBirthday: BlockHeight,
|
walletBirthday: BlockHeight,
|
||||||
completion: @escaping (Result<Initializer.InitializationResult, Error>) -> Void
|
completion: @escaping (Result<Initializer.InitializationResult, Error>) -> Void
|
||||||
) {
|
) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
return try await self.synchronizer.prepare(with: seed, viewingKeys: viewingKeys, walletBirthday: walletBirthday)
|
return try await self.synchronizer.prepare(with: seed, viewingKeys: viewingKeys, walletBirthday: walletBirthday)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func start(retry: Bool, completion: @escaping (Error?) -> Void) {
|
public func start(retry: Bool, completion: @escaping (Error?) -> Void) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
try await self.synchronizer.start(retry: retry)
|
try await self.synchronizer.start(retry: retry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func stop(completion: @escaping () -> Void) {
|
public func stop(completion: @escaping () -> Void) {
|
||||||
executeAction(completion) {
|
AsyncToClosureGateway.executeAction(completion) {
|
||||||
await self.synchronizer.stop()
|
await self.synchronizer.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getSaplingAddress(accountIndex: Int, completion: @escaping (Result<SaplingAddress, Error>) -> Void) {
|
public func getSaplingAddress(accountIndex: Int, completion: @escaping (Result<SaplingAddress, Error>) -> Void) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
try await self.synchronizer.getSaplingAddress(accountIndex: accountIndex)
|
try await self.synchronizer.getSaplingAddress(accountIndex: accountIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getUnifiedAddress(accountIndex: Int, completion: @escaping (Result<UnifiedAddress, Error>) -> Void) {
|
public func getUnifiedAddress(accountIndex: Int, completion: @escaping (Result<UnifiedAddress, Error>) -> Void) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
try await self.synchronizer.getUnifiedAddress(accountIndex: accountIndex)
|
try await self.synchronizer.getUnifiedAddress(accountIndex: accountIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getTransparentAddress(accountIndex: Int, completion: @escaping (Result<TransparentAddress, Error>) -> Void) {
|
public func getTransparentAddress(accountIndex: Int, completion: @escaping (Result<TransparentAddress, Error>) -> Void) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
try await self.synchronizer.getTransparentAddress(accountIndex: accountIndex)
|
try await self.synchronizer.getTransparentAddress(accountIndex: accountIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ extension ClosureSDKSynchronizer: ClosureSynchronizer {
|
||||||
memo: Memo?,
|
memo: Memo?,
|
||||||
completion: @escaping (Result<PendingTransactionEntity, Error>) -> Void
|
completion: @escaping (Result<PendingTransactionEntity, Error>) -> Void
|
||||||
) {
|
) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
try await self.synchronizer.sendToAddress(spendingKey: spendingKey, zatoshi: zatoshi, toAddress: toAddress, memo: memo)
|
try await self.synchronizer.sendToAddress(spendingKey: spendingKey, zatoshi: zatoshi, toAddress: toAddress, memo: memo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,37 +90,37 @@ extension ClosureSDKSynchronizer: ClosureSynchronizer {
|
||||||
shieldingThreshold: Zatoshi,
|
shieldingThreshold: Zatoshi,
|
||||||
completion: @escaping (Result<PendingTransactionEntity, Error>) -> Void
|
completion: @escaping (Result<PendingTransactionEntity, Error>) -> Void
|
||||||
) {
|
) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
try await self.synchronizer.shieldFunds(spendingKey: spendingKey, memo: memo, shieldingThreshold: shieldingThreshold)
|
try await self.synchronizer.shieldFunds(spendingKey: spendingKey, memo: memo, shieldingThreshold: shieldingThreshold)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func cancelSpend(transaction: PendingTransactionEntity, completion: @escaping (Bool) -> Void) {
|
public func cancelSpend(transaction: PendingTransactionEntity, completion: @escaping (Bool) -> Void) {
|
||||||
executeAction(completion) {
|
AsyncToClosureGateway.executeAction(completion) {
|
||||||
await self.synchronizer.cancelSpend(transaction: transaction)
|
await self.synchronizer.cancelSpend(transaction: transaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func pendingTransactions(completion: @escaping ([PendingTransactionEntity]) -> Void) {
|
public func pendingTransactions(completion: @escaping ([PendingTransactionEntity]) -> Void) {
|
||||||
executeAction(completion) {
|
AsyncToClosureGateway.executeAction(completion) {
|
||||||
await self.synchronizer.pendingTransactions
|
await self.synchronizer.pendingTransactions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func clearedTransactions(completion: @escaping ([ZcashTransaction.Overview]) -> Void) {
|
public func clearedTransactions(completion: @escaping ([ZcashTransaction.Overview]) -> Void) {
|
||||||
executeAction(completion) {
|
AsyncToClosureGateway.executeAction(completion) {
|
||||||
await self.synchronizer.clearedTransactions
|
await self.synchronizer.clearedTransactions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func sentTranscations(completion: @escaping ([ZcashTransaction.Sent]) -> Void) {
|
public func sentTranscations(completion: @escaping ([ZcashTransaction.Sent]) -> Void) {
|
||||||
executeAction(completion) {
|
AsyncToClosureGateway.executeAction(completion) {
|
||||||
await self.synchronizer.sentTransactions
|
await self.synchronizer.sentTransactions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func receivedTransactions(completion: @escaping ([ZcashTransaction.Received]) -> Void) {
|
public func receivedTransactions(completion: @escaping ([ZcashTransaction.Received]) -> Void) {
|
||||||
executeAction(completion) {
|
AsyncToClosureGateway.executeAction(completion) {
|
||||||
await self.synchronizer.receivedTransactions
|
await self.synchronizer.receivedTransactions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,31 +128,31 @@ extension ClosureSDKSynchronizer: ClosureSynchronizer {
|
||||||
public func paginatedTransactions(of kind: TransactionKind) -> PaginatedTransactionRepository { synchronizer.paginatedTransactions(of: kind) }
|
public func paginatedTransactions(of kind: TransactionKind) -> PaginatedTransactionRepository { synchronizer.paginatedTransactions(of: kind) }
|
||||||
|
|
||||||
public func getMemos(for transaction: ZcashTransaction.Overview, completion: @escaping (Result<[Memo], Error>) -> Void) {
|
public func getMemos(for transaction: ZcashTransaction.Overview, completion: @escaping (Result<[Memo], Error>) -> Void) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
try await self.synchronizer.getMemos(for: transaction)
|
try await self.synchronizer.getMemos(for: transaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getMemos(for receivedTransaction: ZcashTransaction.Received, completion: @escaping (Result<[Memo], Error>) -> Void) {
|
public func getMemos(for receivedTransaction: ZcashTransaction.Received, completion: @escaping (Result<[Memo], Error>) -> Void) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
try await self.synchronizer.getMemos(for: receivedTransaction)
|
try await self.synchronizer.getMemos(for: receivedTransaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getMemos(for sentTransaction: ZcashTransaction.Sent, completion: @escaping (Result<[Memo], Error>) -> Void) {
|
public func getMemos(for sentTransaction: ZcashTransaction.Sent, completion: @escaping (Result<[Memo], Error>) -> Void) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
try await self.synchronizer.getMemos(for: sentTransaction)
|
try await self.synchronizer.getMemos(for: sentTransaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getRecipients(for transaction: ZcashTransaction.Overview, completion: @escaping ([TransactionRecipient]) -> Void) {
|
public func getRecipients(for transaction: ZcashTransaction.Overview, completion: @escaping ([TransactionRecipient]) -> Void) {
|
||||||
executeAction(completion) {
|
AsyncToClosureGateway.executeAction(completion) {
|
||||||
await self.synchronizer.getRecipients(for: transaction)
|
await self.synchronizer.getRecipients(for: transaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getRecipients(for transaction: ZcashTransaction.Sent, completion: @escaping ([TransactionRecipient]) -> Void) {
|
public func getRecipients(for transaction: ZcashTransaction.Sent, completion: @escaping ([TransactionRecipient]) -> Void) {
|
||||||
executeAction(completion) {
|
AsyncToClosureGateway.executeAction(completion) {
|
||||||
await self.synchronizer.getRecipients(for: transaction)
|
await self.synchronizer.getRecipients(for: transaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,37 +162,37 @@ extension ClosureSDKSynchronizer: ClosureSynchronizer {
|
||||||
limit: Int,
|
limit: Int,
|
||||||
completion: @escaping (Result<[ZcashTransaction.Overview], Error>) -> Void
|
completion: @escaping (Result<[ZcashTransaction.Overview], Error>) -> Void
|
||||||
) {
|
) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
try await self.synchronizer.allConfirmedTransactions(from: transaction, limit: limit)
|
try await self.synchronizer.allConfirmedTransactions(from: transaction, limit: limit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func latestHeight(completion: @escaping (Result<BlockHeight, Error>) -> Void) {
|
public func latestHeight(completion: @escaping (Result<BlockHeight, Error>) -> Void) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
try await self.synchronizer.latestHeight()
|
try await self.synchronizer.latestHeight()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func refreshUTXOs(address: TransparentAddress, from height: BlockHeight, completion: @escaping (Result<RefreshedUTXOs, Error>) -> Void) {
|
public func refreshUTXOs(address: TransparentAddress, from height: BlockHeight, completion: @escaping (Result<RefreshedUTXOs, Error>) -> Void) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
try await self.synchronizer.refreshUTXOs(address: address, from: height)
|
try await self.synchronizer.refreshUTXOs(address: address, from: height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getTransparentBalance(accountIndex: Int, completion: @escaping (Result<WalletBalance, Error>) -> Void) {
|
public func getTransparentBalance(accountIndex: Int, completion: @escaping (Result<WalletBalance, Error>) -> Void) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
try await self.synchronizer.getTransparentBalance(accountIndex: accountIndex)
|
try await self.synchronizer.getTransparentBalance(accountIndex: accountIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getShieldedBalance(accountIndex: Int, completion: @escaping (Result<Zatoshi, Error>) -> Void) {
|
public func getShieldedBalance(accountIndex: Int, completion: @escaping (Result<Zatoshi, Error>) -> Void) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
try await self.synchronizer.getShieldedBalance(accountIndex: accountIndex)
|
try await self.synchronizer.getShieldedBalance(accountIndex: accountIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getShieldedVerifiedBalance(accountIndex: Int, completion: @escaping (Result<Zatoshi, Error>) -> Void) {
|
public func getShieldedVerifiedBalance(accountIndex: Int, completion: @escaping (Result<Zatoshi, Error>) -> Void) {
|
||||||
executeThrowingAction(completion) {
|
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||||
try await self.synchronizer.getShieldedVerifiedBalance(accountIndex: accountIndex)
|
try await self.synchronizer.getShieldedVerifiedBalance(accountIndex: accountIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,41 +204,3 @@ extension ClosureSDKSynchronizer: ClosureSynchronizer {
|
||||||
public func rewind(_ policy: RewindPolicy) -> CompletablePublisher<Error> { synchronizer.rewind(policy) }
|
public func rewind(_ policy: RewindPolicy) -> CompletablePublisher<Error> { synchronizer.rewind(policy) }
|
||||||
public func wipe() -> CompletablePublisher<Error> { synchronizer.wipe() }
|
public func wipe() -> CompletablePublisher<Error> { synchronizer.wipe() }
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ClosureSDKSynchronizer {
|
|
||||||
private func executeAction(_ completion: @escaping () -> Void, action: @escaping () async -> Void) {
|
|
||||||
Task {
|
|
||||||
await action()
|
|
||||||
completion()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func executeAction<R>(_ completion: @escaping (R) -> Void, action: @escaping () async -> R) {
|
|
||||||
Task {
|
|
||||||
let result = await action()
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func executeThrowingAction(_ completion: @escaping (Error?) -> Void, action: @escaping () async throws -> Void) {
|
|
||||||
Task {
|
|
||||||
do {
|
|
||||||
try await action()
|
|
||||||
completion(nil)
|
|
||||||
} catch {
|
|
||||||
completion(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func executeThrowingAction<R>(_ completion: @escaping (Result<R, Error>) -> Void, action: @escaping () async throws -> R) {
|
|
||||||
Task {
|
|
||||||
do {
|
|
||||||
let result = try await action()
|
|
||||||
completion(.success(result))
|
|
||||||
} catch {
|
|
||||||
completion(.failure(error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -36,37 +36,37 @@ extension CombineSDKSynchronizer: CombineSynchronizer {
|
||||||
viewingKeys: [UnifiedFullViewingKey],
|
viewingKeys: [UnifiedFullViewingKey],
|
||||||
walletBirthday: BlockHeight
|
walletBirthday: BlockHeight
|
||||||
) -> SinglePublisher<Initializer.InitializationResult, Error> {
|
) -> SinglePublisher<Initializer.InitializationResult, Error> {
|
||||||
return executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
return try await self.synchronizer.prepare(with: seed, viewingKeys: viewingKeys, walletBirthday: walletBirthday)
|
return try await self.synchronizer.prepare(with: seed, viewingKeys: viewingKeys, walletBirthday: walletBirthday)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func start(retry: Bool) -> CompletablePublisher<Error> {
|
public func start(retry: Bool) -> CompletablePublisher<Error> {
|
||||||
return executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
try await self.synchronizer.start(retry: retry)
|
try await self.synchronizer.start(retry: retry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func stop() -> CompletablePublisher<Never> {
|
public func stop() -> CompletablePublisher<Never> {
|
||||||
return executeAction() {
|
AsyncToCombineGateway.executeAction() {
|
||||||
await self.synchronizer.stop()
|
await self.synchronizer.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getSaplingAddress(accountIndex: Int) -> SinglePublisher<SaplingAddress, Error> {
|
public func getSaplingAddress(accountIndex: Int) -> SinglePublisher<SaplingAddress, Error> {
|
||||||
return executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
try await self.synchronizer.getSaplingAddress(accountIndex: accountIndex)
|
try await self.synchronizer.getSaplingAddress(accountIndex: accountIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getUnifiedAddress(accountIndex: Int) -> SinglePublisher<UnifiedAddress, Error> {
|
public func getUnifiedAddress(accountIndex: Int) -> SinglePublisher<UnifiedAddress, Error> {
|
||||||
return executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
try await self.synchronizer.getUnifiedAddress(accountIndex: accountIndex)
|
try await self.synchronizer.getUnifiedAddress(accountIndex: accountIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getTransparentAddress(accountIndex: Int) -> SinglePublisher<TransparentAddress, Error> {
|
public func getTransparentAddress(accountIndex: Int) -> SinglePublisher<TransparentAddress, Error> {
|
||||||
return executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
try await self.synchronizer.getTransparentAddress(accountIndex: accountIndex)
|
try await self.synchronizer.getTransparentAddress(accountIndex: accountIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ extension CombineSDKSynchronizer: CombineSynchronizer {
|
||||||
toAddress: Recipient,
|
toAddress: Recipient,
|
||||||
memo: Memo?
|
memo: Memo?
|
||||||
) -> SinglePublisher<PendingTransactionEntity, Error> {
|
) -> SinglePublisher<PendingTransactionEntity, Error> {
|
||||||
return executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
try await self.synchronizer.sendToAddress(spendingKey: spendingKey, zatoshi: zatoshi, toAddress: toAddress, memo: memo)
|
try await self.synchronizer.sendToAddress(spendingKey: spendingKey, zatoshi: zatoshi, toAddress: toAddress, memo: memo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,37 +87,37 @@ extension CombineSDKSynchronizer: CombineSynchronizer {
|
||||||
memo: Memo,
|
memo: Memo,
|
||||||
shieldingThreshold: Zatoshi
|
shieldingThreshold: Zatoshi
|
||||||
) -> SinglePublisher<PendingTransactionEntity, Error> {
|
) -> SinglePublisher<PendingTransactionEntity, Error> {
|
||||||
return executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
try await self.synchronizer.shieldFunds(spendingKey: spendingKey, memo: memo, shieldingThreshold: shieldingThreshold)
|
try await self.synchronizer.shieldFunds(spendingKey: spendingKey, memo: memo, shieldingThreshold: shieldingThreshold)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func cancelSpend(transaction: PendingTransactionEntity) -> SinglePublisher<Bool, Never> {
|
public func cancelSpend(transaction: PendingTransactionEntity) -> SinglePublisher<Bool, Never> {
|
||||||
executeAction() {
|
AsyncToCombineGateway.executeAction() {
|
||||||
await self.synchronizer.cancelSpend(transaction: transaction)
|
await self.synchronizer.cancelSpend(transaction: transaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var pendingTransactions: SinglePublisher<[PendingTransactionEntity], Never> {
|
public var pendingTransactions: SinglePublisher<[PendingTransactionEntity], Never> {
|
||||||
executeAction() {
|
AsyncToCombineGateway.executeAction() {
|
||||||
await self.synchronizer.pendingTransactions
|
await self.synchronizer.pendingTransactions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var clearedTransactions: SinglePublisher<[ZcashTransaction.Overview], Never> {
|
public var clearedTransactions: SinglePublisher<[ZcashTransaction.Overview], Never> {
|
||||||
executeAction() {
|
AsyncToCombineGateway.executeAction() {
|
||||||
await self.synchronizer.clearedTransactions
|
await self.synchronizer.clearedTransactions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var sentTransactions: SinglePublisher<[ZcashTransaction.Sent], Never> {
|
public var sentTransactions: SinglePublisher<[ZcashTransaction.Sent], Never> {
|
||||||
executeAction() {
|
AsyncToCombineGateway.executeAction() {
|
||||||
await self.synchronizer.sentTransactions
|
await self.synchronizer.sentTransactions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var receivedTransactions: SinglePublisher<[ZcashTransaction.Received], Never> {
|
public var receivedTransactions: SinglePublisher<[ZcashTransaction.Received], Never> {
|
||||||
executeAction() {
|
AsyncToCombineGateway.executeAction() {
|
||||||
await self.synchronizer.receivedTransactions
|
await self.synchronizer.receivedTransactions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,67 +125,67 @@ extension CombineSDKSynchronizer: CombineSynchronizer {
|
||||||
public func paginatedTransactions(of kind: TransactionKind) -> PaginatedTransactionRepository { synchronizer.paginatedTransactions(of: kind) }
|
public func paginatedTransactions(of kind: TransactionKind) -> PaginatedTransactionRepository { synchronizer.paginatedTransactions(of: kind) }
|
||||||
|
|
||||||
public func getMemos(for transaction: ZcashTransaction.Overview) -> SinglePublisher<[Memo], Error> {
|
public func getMemos(for transaction: ZcashTransaction.Overview) -> SinglePublisher<[Memo], Error> {
|
||||||
executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
try await self.synchronizer.getMemos(for: transaction)
|
try await self.synchronizer.getMemos(for: transaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getMemos(for receivedTransaction: ZcashTransaction.Received) -> SinglePublisher<[Memo], Error> {
|
public func getMemos(for receivedTransaction: ZcashTransaction.Received) -> SinglePublisher<[Memo], Error> {
|
||||||
executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
try await self.synchronizer.getMemos(for: receivedTransaction)
|
try await self.synchronizer.getMemos(for: receivedTransaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getMemos(for sentTransaction: ZcashTransaction.Sent) -> SinglePublisher<[Memo], Error> {
|
public func getMemos(for sentTransaction: ZcashTransaction.Sent) -> SinglePublisher<[Memo], Error> {
|
||||||
executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
try await self.synchronizer.getMemos(for: sentTransaction)
|
try await self.synchronizer.getMemos(for: sentTransaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getRecipients(for transaction: ZcashTransaction.Overview) -> SinglePublisher<[TransactionRecipient], Never> {
|
public func getRecipients(for transaction: ZcashTransaction.Overview) -> SinglePublisher<[TransactionRecipient], Never> {
|
||||||
executeAction() {
|
AsyncToCombineGateway.executeAction() {
|
||||||
await self.synchronizer.getRecipients(for: transaction)
|
await self.synchronizer.getRecipients(for: transaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getRecipients(for transaction: ZcashTransaction.Sent) -> SinglePublisher<[TransactionRecipient], Never> {
|
public func getRecipients(for transaction: ZcashTransaction.Sent) -> SinglePublisher<[TransactionRecipient], Never> {
|
||||||
executeAction() {
|
AsyncToCombineGateway.executeAction() {
|
||||||
await self.synchronizer.getRecipients(for: transaction)
|
await self.synchronizer.getRecipients(for: transaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func allConfirmedTransactions(from transaction: ZcashTransaction.Overview, limit: Int) -> SinglePublisher<[ZcashTransaction.Overview], Error> {
|
public func allConfirmedTransactions(from transaction: ZcashTransaction.Overview, limit: Int) -> SinglePublisher<[ZcashTransaction.Overview], Error> {
|
||||||
executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
try await self.synchronizer.allConfirmedTransactions(from: transaction, limit: limit)
|
try await self.synchronizer.allConfirmedTransactions(from: transaction, limit: limit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func latestHeight() -> SinglePublisher<BlockHeight, Error> {
|
public func latestHeight() -> SinglePublisher<BlockHeight, Error> {
|
||||||
return executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
try await self.synchronizer.latestHeight()
|
try await self.synchronizer.latestHeight()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func refreshUTXOs(address: TransparentAddress, from height: BlockHeight) -> SinglePublisher<RefreshedUTXOs, Error> {
|
public func refreshUTXOs(address: TransparentAddress, from height: BlockHeight) -> SinglePublisher<RefreshedUTXOs, Error> {
|
||||||
return executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
try await self.synchronizer.refreshUTXOs(address: address, from: height)
|
try await self.synchronizer.refreshUTXOs(address: address, from: height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getTransparentBalance(accountIndex: Int) -> SinglePublisher<WalletBalance, Error> {
|
public func getTransparentBalance(accountIndex: Int) -> SinglePublisher<WalletBalance, Error> {
|
||||||
return executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
try await self.synchronizer.getTransparentBalance(accountIndex: accountIndex)
|
try await self.synchronizer.getTransparentBalance(accountIndex: accountIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getShieldedBalance(accountIndex: Int = 0) -> SinglePublisher<Zatoshi, Error> {
|
public func getShieldedBalance(accountIndex: Int = 0) -> SinglePublisher<Zatoshi, Error> {
|
||||||
return executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
try await synchronizer.getShieldedBalance(accountIndex: accountIndex)
|
try await synchronizer.getShieldedBalance(accountIndex: accountIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getShieldedVerifiedBalance(accountIndex: Int = 0) -> SinglePublisher<Zatoshi, Error> {
|
public func getShieldedVerifiedBalance(accountIndex: Int = 0) -> SinglePublisher<Zatoshi, Error> {
|
||||||
return executeThrowingAction() {
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
try await synchronizer.getShieldedVerifiedBalance(accountIndex: accountIndex)
|
try await synchronizer.getShieldedVerifiedBalance(accountIndex: accountIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,53 +193,3 @@ extension CombineSDKSynchronizer: CombineSynchronizer {
|
||||||
public func rewind(_ policy: RewindPolicy) -> CompletablePublisher<Error> { synchronizer.rewind(policy) }
|
public func rewind(_ policy: RewindPolicy) -> CompletablePublisher<Error> { synchronizer.rewind(policy) }
|
||||||
public func wipe() -> CompletablePublisher<Error> { synchronizer.wipe() }
|
public func wipe() -> CompletablePublisher<Error> { synchronizer.wipe() }
|
||||||
}
|
}
|
||||||
|
|
||||||
extension CombineSDKSynchronizer {
|
|
||||||
private func executeAction(action: @escaping () async -> Void) -> CompletablePublisher<Never> {
|
|
||||||
let subject = PassthroughSubject<Void, Never>()
|
|
||||||
Task {
|
|
||||||
await action()
|
|
||||||
subject.send(completion: .finished)
|
|
||||||
}
|
|
||||||
return subject.eraseToAnyPublisher()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func executeAction<R>(action: @escaping () async -> R) -> SinglePublisher<R, Never> {
|
|
||||||
let subject = PassthroughSubject<R, Never>()
|
|
||||||
Task {
|
|
||||||
let result = await action()
|
|
||||||
subject.send(result)
|
|
||||||
subject.send(completion: .finished)
|
|
||||||
}
|
|
||||||
return subject.eraseToAnyPublisher()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func executeThrowingAction(action: @escaping () async throws -> Void) -> CompletablePublisher<Error> {
|
|
||||||
let subject = PassthroughSubject<Void, Error>()
|
|
||||||
Task {
|
|
||||||
do {
|
|
||||||
try await action()
|
|
||||||
subject.send(completion: .finished)
|
|
||||||
} catch {
|
|
||||||
subject.send(completion: .failure(error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return subject.eraseToAnyPublisher()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func executeThrowingAction<R>(action: @escaping () async throws -> R) -> SinglePublisher<R, Error> {
|
|
||||||
let subject = PassthroughSubject<R, Error>()
|
|
||||||
Task {
|
|
||||||
do {
|
|
||||||
let result = try await action()
|
|
||||||
subject.send(result)
|
|
||||||
subject.send(completion: .finished)
|
|
||||||
} catch {
|
|
||||||
subject.send(completion: .failure(error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return subject.eraseToAnyPublisher()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -458,21 +458,13 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getShieldedBalance(accountIndex: Int = 0) async throws -> Zatoshi {
|
public func getShieldedBalance(accountIndex: Int = 0) async throws -> Zatoshi {
|
||||||
let balance = try await initializer.rustBackend.getBalance(
|
let balance = try await initializer.rustBackend.getBalance(account: Int32(accountIndex))
|
||||||
dbData: initializer.dataDbURL,
|
|
||||||
account: Int32(accountIndex),
|
|
||||||
networkType: network.networkType
|
|
||||||
)
|
|
||||||
|
|
||||||
return Zatoshi(balance)
|
return Zatoshi(balance)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getShieldedVerifiedBalance(accountIndex: Int = 0) async throws -> Zatoshi {
|
public func getShieldedVerifiedBalance(accountIndex: Int = 0) async throws -> Zatoshi {
|
||||||
let balance = try await initializer.rustBackend.getVerifiedBalance(
|
let balance = try await initializer.rustBackend.getVerifiedBalance(account: Int32(accountIndex))
|
||||||
dbData: initializer.dataDbURL,
|
|
||||||
account: Int32(accountIndex),
|
|
||||||
networkType: network.networkType
|
|
||||||
)
|
|
||||||
|
|
||||||
return Zatoshi(balance)
|
return Zatoshi(balance)
|
||||||
}
|
}
|
||||||
|
@ -617,7 +609,6 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
|
|
||||||
newState = await snapshotState(status: newStatus)
|
newState = await snapshotState(status: newStatus)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
newState = await SynchronizerState(
|
newState = await SynchronizerState(
|
||||||
syncSessionID: syncSession.value,
|
syncSessionID: syncSession.value,
|
||||||
shieldedBalance: latestState.shieldedBalance,
|
shieldedBalance: latestState.shieldedBalance,
|
||||||
|
|
|
@ -5,17 +5,14 @@
|
||||||
// Created by Francisco Gindre on 10/8/20.
|
// Created by Francisco Gindre on 10/8/20.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public protocol KeyValidation {
|
public protocol KeyValidation {
|
||||||
func isValidUnifiedFullViewingKey(_ ufvk: String) -> Bool
|
func isValidUnifiedFullViewingKey(_ ufvk: String) -> Bool
|
||||||
|
|
||||||
func isValidTransparentAddress(_ tAddress: String) -> Bool
|
func isValidTransparentAddress(_ tAddress: String) -> Bool
|
||||||
|
|
||||||
func isValidSaplingAddress(_ zAddress: String) -> Bool
|
func isValidSaplingAddress(_ zAddress: String) -> Bool
|
||||||
|
|
||||||
func isValidSaplingExtendedSpendingKey(_ extsk: String) -> Bool
|
func isValidSaplingExtendedSpendingKey(_ extsk: String) -> Bool
|
||||||
|
|
||||||
func isValidUnifiedAddress(_ unifiedAddress: String) -> Bool
|
func isValidUnifiedAddress(_ unifiedAddress: String) -> Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,26 +22,39 @@ public protocol KeyDeriving {
|
||||||
/// - Parameter accountNumber: `Int` with the account number
|
/// - Parameter accountNumber: `Int` with the account number
|
||||||
/// - Throws `.unableToDerive` if there's a problem deriving this key
|
/// - Throws `.unableToDerive` if there's a problem deriving this key
|
||||||
/// - Returns a `UnifiedSpendingKey`
|
/// - Returns a `UnifiedSpendingKey`
|
||||||
func deriveUnifiedSpendingKey(seed: [UInt8], accountIndex: Int) throws -> UnifiedSpendingKey
|
func deriveUnifiedSpendingKey(seed: [UInt8], accountIndex: Int) async throws -> UnifiedSpendingKey
|
||||||
|
func deriveUnifiedSpendingKey(seed: [UInt8], accountIndex: Int, completion: @escaping (Result<UnifiedSpendingKey, Error>) -> Void)
|
||||||
|
func deriveUnifiedSpendingKey(seed: [UInt8], accountIndex: Int) -> SinglePublisher<UnifiedSpendingKey, Error>
|
||||||
|
|
||||||
|
/// Given a spending key, return the associated viewing key.
|
||||||
|
/// - Parameter spendingKey: the `UnifiedSpendingKey` from which to derive the `UnifiedFullViewingKey` from.
|
||||||
|
/// - Returns: the viewing key that corresponds to the spending key.
|
||||||
|
func deriveUnifiedFullViewingKey(from spendingKey: UnifiedSpendingKey) async throws -> UnifiedFullViewingKey
|
||||||
|
func deriveUnifiedFullViewingKey(from spendingKey: UnifiedSpendingKey, completion: @escaping (Result<UnifiedFullViewingKey, Error>) -> Void)
|
||||||
|
func deriveUnifiedFullViewingKey(from spendingKey: UnifiedSpendingKey) -> SinglePublisher<UnifiedFullViewingKey, Error>
|
||||||
|
|
||||||
/// Extracts the `SaplingAddress` from the given `UnifiedAddress`
|
/// Extracts the `SaplingAddress` from the given `UnifiedAddress`
|
||||||
/// - Parameter address: the `UnifiedAddress`
|
/// - Parameter address: the `UnifiedAddress`
|
||||||
/// - Throws `KeyDerivationErrors.receiverNotFound` if the receiver is not present
|
/// - Throws `KeyDerivationErrors.receiverNotFound` if the receiver is not present
|
||||||
static func saplingReceiver(from unifiedAddress: UnifiedAddress) throws -> SaplingAddress
|
func saplingReceiver(from unifiedAddress: UnifiedAddress) throws -> SaplingAddress
|
||||||
|
|
||||||
/// Extracts the `TransparentAddress` from the given `UnifiedAddress`
|
/// Extracts the `TransparentAddress` from the given `UnifiedAddress`
|
||||||
/// - Parameter address: the `UnifiedAddress`
|
/// - Parameter address: the `UnifiedAddress`
|
||||||
/// - Throws `KeyDerivationErrors.receiverNotFound` if the receiver is not present
|
/// - Throws `KeyDerivationErrors.receiverNotFound` if the receiver is not present
|
||||||
static func transparentReceiver(from unifiedAddress: UnifiedAddress) throws -> TransparentAddress
|
func transparentReceiver(from unifiedAddress: UnifiedAddress) throws -> TransparentAddress
|
||||||
|
|
||||||
/// Extracts the `UnifiedAddress.ReceiverTypecodes` from the given `UnifiedAddress`
|
/// Extracts the `UnifiedAddress.ReceiverTypecodes` from the given `UnifiedAddress`
|
||||||
/// - Parameter address: the `UnifiedAddress`
|
/// - Parameter address: the `UnifiedAddress`
|
||||||
/// - Throws
|
/// - Throws
|
||||||
static func receiverTypecodesFromUnifiedAddress(_ address: UnifiedAddress) throws -> [UnifiedAddress.ReceiverTypecodes]
|
func receiverTypecodesFromUnifiedAddress(_ address: UnifiedAddress) throws -> [UnifiedAddress.ReceiverTypecodes]
|
||||||
|
|
||||||
|
static func getAddressMetadata(_ addr: String) -> AddressMetadata?
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum KeyDerivationErrors: Error {
|
public enum KeyDerivationErrors: Error {
|
||||||
case derivationError(underlyingError: Error)
|
case derivationError(underlyingError: Error)
|
||||||
|
// When something happens that is not related to derivation itself happens. For example if self is nil in closure.
|
||||||
|
case genericOtherError
|
||||||
case unableToDerive
|
case unableToDerive
|
||||||
case invalidInput
|
case invalidInput
|
||||||
case invalidUnifiedAddress
|
case invalidUnifiedAddress
|
||||||
|
@ -52,31 +62,43 @@ public enum KeyDerivationErrors: Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DerivationTool: KeyDeriving {
|
public class DerivationTool: KeyDeriving {
|
||||||
static var rustwelding: ZcashRustBackendWelding.Type = ZcashRustBackend.self
|
let backend: ZcashKeyDerivationBackendWelding
|
||||||
|
|
||||||
var networkType: NetworkType
|
init(networkType: NetworkType) {
|
||||||
|
self.backend = ZcashKeyDerivationBackend(networkType: networkType)
|
||||||
public init(networkType: NetworkType) {
|
|
||||||
self.networkType = networkType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func saplingReceiver(from unifiedAddress: UnifiedAddress) throws -> SaplingAddress {
|
public func saplingReceiver(from unifiedAddress: UnifiedAddress) throws -> SaplingAddress {
|
||||||
try rustwelding.getSaplingReceiver(for: unifiedAddress)
|
try backend.getSaplingReceiver(for: unifiedAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func transparentReceiver(from unifiedAddress: UnifiedAddress) throws -> TransparentAddress {
|
public func transparentReceiver(from unifiedAddress: UnifiedAddress) throws -> TransparentAddress {
|
||||||
try rustwelding.getTransparentReceiver(for: unifiedAddress)
|
try backend.getTransparentReceiver(for: unifiedAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func getAddressMetadata(_ addr: String) -> AddressMetadata? {
|
public static func getAddressMetadata(_ addr: String) -> AddressMetadata? {
|
||||||
rustwelding.getAddressMetadata(addr)
|
ZcashKeyDerivationBackend.getAddressMetadata(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a spending key, return the associated viewing key.
|
/// Given a spending key, return the associated viewing key.
|
||||||
/// - Parameter spendingKey: the `UnifiedSpendingKey` from which to derive the `UnifiedFullViewingKey` from.
|
/// - Parameter spendingKey: the `UnifiedSpendingKey` from which to derive the `UnifiedFullViewingKey` from.
|
||||||
/// - Returns: the viewing key that corresponds to the spending key.
|
/// - Returns: the viewing key that corresponds to the spending key.
|
||||||
public func deriveUnifiedFullViewingKey(from spendingKey: UnifiedSpendingKey) throws -> UnifiedFullViewingKey {
|
public func deriveUnifiedFullViewingKey(from spendingKey: UnifiedSpendingKey) async throws -> UnifiedFullViewingKey {
|
||||||
try DerivationTool.rustwelding.deriveUnifiedFullViewingKey(from: spendingKey, networkType: self.networkType)
|
try await backend.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func deriveUnifiedFullViewingKey(from spendingKey: UnifiedSpendingKey, completion: @escaping (Result<UnifiedFullViewingKey, Error>) -> Void) {
|
||||||
|
AsyncToClosureGateway.executeThrowingAction(completion) { [weak self] in
|
||||||
|
guard let self else { throw KeyDerivationErrors.genericOtherError }
|
||||||
|
return try await self.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func deriveUnifiedFullViewingKey(from spendingKey: UnifiedSpendingKey) -> SinglePublisher<UnifiedFullViewingKey, Error> {
|
||||||
|
AsyncToCombineGateway.executeThrowingAction() { [weak self] in
|
||||||
|
guard let self else { throw KeyDerivationErrors.genericOtherError }
|
||||||
|
return try await self.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a seed and a number of accounts, return the associated spending keys.
|
/// Given a seed and a number of accounts, return the associated spending keys.
|
||||||
|
@ -84,24 +106,34 @@ public class DerivationTool: KeyDeriving {
|
||||||
/// - Parameter numberOfAccounts: the number of accounts to use. Multiple accounts are not fully
|
/// - Parameter numberOfAccounts: the number of accounts to use. Multiple accounts are not fully
|
||||||
/// supported so the default value of 1 is recommended.
|
/// supported so the default value of 1 is recommended.
|
||||||
/// - Returns: the spending keys that correspond to the seed, formatted as Strings.
|
/// - Returns: the spending keys that correspond to the seed, formatted as Strings.
|
||||||
public func deriveUnifiedSpendingKey(seed: [UInt8], accountIndex: Int) throws -> UnifiedSpendingKey {
|
public func deriveUnifiedSpendingKey(seed: [UInt8], accountIndex: Int) async throws -> UnifiedSpendingKey {
|
||||||
guard accountIndex >= 0, let accountIndex = Int32(exactly: accountIndex) else {
|
guard accountIndex >= 0, let accountIndex = Int32(exactly: accountIndex) else {
|
||||||
throw KeyDerivationErrors.invalidInput
|
throw KeyDerivationErrors.invalidInput
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
return try DerivationTool.rustwelding.deriveUnifiedSpendingKey(
|
return try await backend.deriveUnifiedSpendingKey(from: seed, accountIndex: accountIndex)
|
||||||
from: seed,
|
|
||||||
accountIndex: accountIndex,
|
|
||||||
networkType: self.networkType
|
|
||||||
)
|
|
||||||
} catch {
|
} catch {
|
||||||
throw KeyDerivationErrors.unableToDerive
|
throw KeyDerivationErrors.unableToDerive
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func receiverTypecodesFromUnifiedAddress(_ address: UnifiedAddress) throws -> [UnifiedAddress.ReceiverTypecodes] {
|
public func deriveUnifiedSpendingKey(seed: [UInt8], accountIndex: Int, completion: @escaping (Result<UnifiedSpendingKey, Error>) -> Void) {
|
||||||
|
AsyncToClosureGateway.executeThrowingAction(completion) { [weak self] in
|
||||||
|
guard let self else { throw KeyDerivationErrors.genericOtherError }
|
||||||
|
return try await self.deriveUnifiedSpendingKey(seed: seed, accountIndex: accountIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func deriveUnifiedSpendingKey(seed: [UInt8], accountIndex: Int) -> SinglePublisher<UnifiedSpendingKey, Error> {
|
||||||
|
AsyncToCombineGateway.executeThrowingAction() { [weak self] in
|
||||||
|
guard let self else { throw KeyDerivationErrors.genericOtherError }
|
||||||
|
return try await self.deriveUnifiedSpendingKey(seed: seed, accountIndex: accountIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func receiverTypecodesFromUnifiedAddress(_ address: UnifiedAddress) throws -> [UnifiedAddress.ReceiverTypecodes] {
|
||||||
do {
|
do {
|
||||||
return try DerivationTool.rustwelding.receiverTypecodesOnUnifiedAddress(address.stringEncoded)
|
return try backend.receiverTypecodesOnUnifiedAddress(address.stringEncoded)
|
||||||
.map({ UnifiedAddress.ReceiverTypecodes(typecode: $0) })
|
.map({ UnifiedAddress.ReceiverTypecodes(typecode: $0) })
|
||||||
} catch {
|
} catch {
|
||||||
throw KeyDerivationErrors.invalidUnifiedAddress
|
throw KeyDerivationErrors.invalidUnifiedAddress
|
||||||
|
@ -121,23 +153,23 @@ public struct AddressMetadata {
|
||||||
|
|
||||||
extension DerivationTool: KeyValidation {
|
extension DerivationTool: KeyValidation {
|
||||||
public func isValidUnifiedFullViewingKey(_ ufvk: String) -> Bool {
|
public func isValidUnifiedFullViewingKey(_ ufvk: String) -> Bool {
|
||||||
DerivationTool.rustwelding.isValidUnifiedFullViewingKey(ufvk, networkType: networkType)
|
backend.isValidUnifiedFullViewingKey(ufvk)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func isValidUnifiedAddress(_ unifiedAddress: String) -> Bool {
|
public func isValidUnifiedAddress(_ unifiedAddress: String) -> Bool {
|
||||||
DerivationTool.rustwelding.isValidUnifiedAddress(unifiedAddress, networkType: networkType)
|
backend.isValidUnifiedAddress(unifiedAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func isValidTransparentAddress(_ tAddress: String) -> Bool {
|
public func isValidTransparentAddress(_ tAddress: String) -> Bool {
|
||||||
DerivationTool.rustwelding.isValidTransparentAddress(tAddress, networkType: networkType)
|
backend.isValidTransparentAddress(tAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func isValidSaplingAddress(_ zAddress: String) -> Bool {
|
public func isValidSaplingAddress(_ zAddress: String) -> Bool {
|
||||||
DerivationTool.rustwelding.isValidSaplingAddress(zAddress, networkType: networkType)
|
backend.isValidSaplingAddress(zAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func isValidSaplingExtendedSpendingKey(_ extsk: String) -> Bool {
|
public func isValidSaplingExtendedSpendingKey(_ extsk: String) -> Bool {
|
||||||
DerivationTool.rustwelding.isValidSaplingExtendedSpendingKey(extsk, networkType: networkType)
|
backend.isValidSaplingExtendedSpendingKey(extsk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,8 +198,9 @@ extension UnifiedAddress {
|
||||||
/// already validated by another function. only for internal use. Unless you are
|
/// already validated by another function. only for internal use. Unless you are
|
||||||
/// constructing an address from a primitive function of the FFI, you probably
|
/// constructing an address from a primitive function of the FFI, you probably
|
||||||
/// shouldn't be using this..
|
/// shouldn't be using this..
|
||||||
init(validatedEncoding: String) {
|
init(validatedEncoding: String, networkType: NetworkType) {
|
||||||
self.encoding = validatedEncoding
|
self.encoding = validatedEncoding
|
||||||
|
self.networkType = networkType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,22 +239,18 @@ public extension UnifiedSpendingKey {
|
||||||
func map<T>(_ transform: (UnifiedSpendingKey) throws -> T) rethrows -> T {
|
func map<T>(_ transform: (UnifiedSpendingKey) throws -> T) rethrows -> T {
|
||||||
try transform(self)
|
try transform(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deriveFullViewingKey() throws -> UnifiedFullViewingKey {
|
|
||||||
try DerivationTool(networkType: self.network).deriveUnifiedFullViewingKey(from: self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension UnifiedAddress {
|
public extension UnifiedAddress {
|
||||||
/// Extracts the sapling receiver from this UA if available
|
/// Extracts the sapling receiver from this UA if available
|
||||||
/// - Returns: an `Optional<SaplingAddress>`
|
/// - Returns: an `Optional<SaplingAddress>`
|
||||||
func saplingReceiver() throws -> SaplingAddress {
|
func saplingReceiver() throws -> SaplingAddress {
|
||||||
try DerivationTool.saplingReceiver(from: self)
|
try DerivationTool(networkType: networkType).saplingReceiver(from: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts the transparent receiver from this UA if available
|
/// Extracts the transparent receiver from this UA if available
|
||||||
/// - Returns: an `Optional<TransparentAddress>`
|
/// - Returns: an `Optional<TransparentAddress>`
|
||||||
func transparentReceiver() throws -> TransparentAddress {
|
func transparentReceiver() throws -> TransparentAddress {
|
||||||
try DerivationTool.transparentReceiver(from: self)
|
try DerivationTool(networkType: networkType).transparentReceiver(from: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class WalletTransactionEncoder: TransactionEncoder {
|
class WalletTransactionEncoder: TransactionEncoder {
|
||||||
var rustBackend: ZcashRustBackendWelding.Type
|
var rustBackend: ZcashRustBackendWelding
|
||||||
var repository: TransactionRepository
|
var repository: TransactionRepository
|
||||||
let logger: Logger
|
let logger: Logger
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ class WalletTransactionEncoder: TransactionEncoder {
|
||||||
private var networkType: NetworkType
|
private var networkType: NetworkType
|
||||||
|
|
||||||
init(
|
init(
|
||||||
rust: ZcashRustBackendWelding.Type,
|
rustBackend: ZcashRustBackendWelding,
|
||||||
dataDb: URL,
|
dataDb: URL,
|
||||||
fsBlockDbRoot: URL,
|
fsBlockDbRoot: URL,
|
||||||
repository: TransactionRepository,
|
repository: TransactionRepository,
|
||||||
|
@ -28,7 +28,7 @@ class WalletTransactionEncoder: TransactionEncoder {
|
||||||
networkType: NetworkType,
|
networkType: NetworkType,
|
||||||
logger: Logger
|
logger: Logger
|
||||||
) {
|
) {
|
||||||
self.rustBackend = rust
|
self.rustBackend = rustBackend
|
||||||
self.dataDbURL = dataDb
|
self.dataDbURL = dataDb
|
||||||
self.fsBlockDbRoot = fsBlockDbRoot
|
self.fsBlockDbRoot = fsBlockDbRoot
|
||||||
self.repository = repository
|
self.repository = repository
|
||||||
|
@ -40,7 +40,7 @@ class WalletTransactionEncoder: TransactionEncoder {
|
||||||
|
|
||||||
convenience init(initializer: Initializer) {
|
convenience init(initializer: Initializer) {
|
||||||
self.init(
|
self.init(
|
||||||
rust: initializer.rustBackend,
|
rustBackend: initializer.rustBackend,
|
||||||
dataDb: initializer.dataDbURL,
|
dataDb: initializer.dataDbURL,
|
||||||
fsBlockDbRoot: initializer.fsBlockDbRoot,
|
fsBlockDbRoot: initializer.fsBlockDbRoot,
|
||||||
repository: initializer.transactionRepository,
|
repository: initializer.transactionRepository,
|
||||||
|
@ -84,22 +84,14 @@ class WalletTransactionEncoder: TransactionEncoder {
|
||||||
guard ensureParams(spend: self.spendParamsURL, output: self.outputParamsURL) else {
|
guard ensureParams(spend: self.spendParamsURL, output: self.outputParamsURL) else {
|
||||||
throw TransactionEncoderError.missingParams
|
throw TransactionEncoderError.missingParams
|
||||||
}
|
}
|
||||||
|
|
||||||
let txId = await rustBackend.createToAddress(
|
let txId = try await rustBackend.createToAddress(
|
||||||
dbData: self.dataDbURL,
|
|
||||||
usk: spendingKey,
|
usk: spendingKey,
|
||||||
to: address,
|
to: address,
|
||||||
value: zatoshi.amount,
|
value: zatoshi.amount,
|
||||||
memo: memoBytes,
|
memo: memoBytes
|
||||||
spendParamsPath: self.spendParamsURL.path,
|
|
||||||
outputParamsPath: self.outputParamsURL.path,
|
|
||||||
networkType: networkType
|
|
||||||
)
|
)
|
||||||
|
|
||||||
guard txId > 0 else {
|
|
||||||
throw rustBackend.lastError() ?? RustWeldingError.genericError(message: "create spend failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
return Int(txId)
|
return Int(txId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,20 +126,12 @@ class WalletTransactionEncoder: TransactionEncoder {
|
||||||
throw TransactionEncoderError.missingParams
|
throw TransactionEncoderError.missingParams
|
||||||
}
|
}
|
||||||
|
|
||||||
let txId = await rustBackend.shieldFunds(
|
let txId = try await rustBackend.shieldFunds(
|
||||||
dbData: self.dataDbURL,
|
|
||||||
usk: spendingKey,
|
usk: spendingKey,
|
||||||
memo: memo,
|
memo: memo,
|
||||||
shieldingThreshold: shieldingThreshold,
|
shieldingThreshold: shieldingThreshold
|
||||||
spendParamsPath: self.spendParamsURL.path,
|
|
||||||
outputParamsPath: self.outputParamsURL.path,
|
|
||||||
networkType: networkType
|
|
||||||
)
|
)
|
||||||
|
|
||||||
guard txId > 0 else {
|
|
||||||
throw rustBackend.lastError() ?? RustWeldingError.genericError(message: "create spend failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
return Int(txId)
|
return Int(txId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
//
|
||||||
|
// AsyncToClosureGateway.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Michal Fousek on 03.04.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum AsyncToClosureGateway {
|
||||||
|
static func executeAction(_ completion: @escaping () -> Void, action: @escaping () async -> Void) {
|
||||||
|
Task {
|
||||||
|
await action()
|
||||||
|
completion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func executeAction<R>(_ completion: @escaping (R) -> Void, action: @escaping () async -> R) {
|
||||||
|
Task {
|
||||||
|
let result = await action()
|
||||||
|
completion(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func executeThrowingAction(_ completion: @escaping (Error?) -> Void, action: @escaping () async throws -> Void) {
|
||||||
|
Task {
|
||||||
|
do {
|
||||||
|
try await action()
|
||||||
|
completion(nil)
|
||||||
|
} catch {
|
||||||
|
completion(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func executeThrowingAction<R>(_ completion: @escaping (Result<R, Error>) -> Void, action: @escaping () async throws -> R) {
|
||||||
|
Task {
|
||||||
|
do {
|
||||||
|
let result = try await action()
|
||||||
|
completion(.success(result))
|
||||||
|
} catch {
|
||||||
|
completion(.failure(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
//
|
||||||
|
// AsyncToCombineGateway.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Michal Fousek on 03.04.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum AsyncToCombineGateway {
|
||||||
|
static func executeAction(action: @escaping () async -> Void) -> CompletablePublisher<Never> {
|
||||||
|
let subject = PassthroughSubject<Void, Never>()
|
||||||
|
Task {
|
||||||
|
await action()
|
||||||
|
subject.send(completion: .finished)
|
||||||
|
}
|
||||||
|
return subject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
static func executeAction<R>(action: @escaping () async -> R) -> SinglePublisher<R, Never> {
|
||||||
|
let subject = PassthroughSubject<R, Never>()
|
||||||
|
Task {
|
||||||
|
let result = await action()
|
||||||
|
subject.send(result)
|
||||||
|
subject.send(completion: .finished)
|
||||||
|
}
|
||||||
|
return subject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
static func executeThrowingAction(action: @escaping () async throws -> Void) -> CompletablePublisher<Error> {
|
||||||
|
let subject = PassthroughSubject<Void, Error>()
|
||||||
|
Task {
|
||||||
|
do {
|
||||||
|
try await action()
|
||||||
|
subject.send(completion: .finished)
|
||||||
|
} catch {
|
||||||
|
subject.send(completion: .failure(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return subject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
static func executeThrowingAction<R>(action: @escaping () async throws -> R) -> SinglePublisher<R, Error> {
|
||||||
|
let subject = PassthroughSubject<R, Error>()
|
||||||
|
Task {
|
||||||
|
do {
|
||||||
|
let result = try await action()
|
||||||
|
subject.send(result)
|
||||||
|
subject.send(completion: .finished)
|
||||||
|
} catch {
|
||||||
|
subject.send(completion: .failure(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return subject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
//
|
||||||
|
// SpecificCombineTypes.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Michal Fousek on 03.04.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/* These aliases are here to just make the API easier to read. */
|
||||||
|
|
||||||
|
// Publisher which emitts completed or error. No value is emitted.
|
||||||
|
public typealias CompletablePublisher<E: Error> = AnyPublisher<Void, E>
|
||||||
|
// Publisher that either emits one value and then finishes or it emits error.
|
||||||
|
public typealias SinglePublisher = AnyPublisher
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
protocol SyncSessionIDGenerator {
|
protocol SyncSessionIDGenerator {
|
||||||
func nextID() -> UUID
|
func nextID() -> UUID
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,6 @@ import XCTest
|
||||||
class BlockDownloaderTests: XCTestCase {
|
class BlockDownloaderTests: XCTestCase {
|
||||||
let branchID = "2bb40e60"
|
let branchID = "2bb40e60"
|
||||||
let chainName = "main"
|
let chainName = "main"
|
||||||
let testTempDirectory = URL(fileURLWithPath: NSString(
|
|
||||||
string: NSTemporaryDirectory()
|
|
||||||
)
|
|
||||||
.appendingPathComponent("tmp-\(Int.random(in: 0 ... .max))"))
|
|
||||||
|
|
||||||
let testFileManager = FileManager()
|
let testFileManager = FileManager()
|
||||||
var darksideWalletService: DarksideWalletService!
|
var darksideWalletService: DarksideWalletService!
|
||||||
|
@ -24,16 +20,25 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
var service: LightWalletService!
|
var service: LightWalletService!
|
||||||
var storage: CompactBlockRepository!
|
var storage: CompactBlockRepository!
|
||||||
var network = DarksideWalletDNetwork()
|
var network = DarksideWalletDNetwork()
|
||||||
|
var rustBackend: ZcashRustBackendWelding!
|
||||||
|
var testTempDirectory: URL!
|
||||||
|
|
||||||
override func setUp() async throws {
|
override func setUp() async throws {
|
||||||
try await super.setUp()
|
try await super.setUp()
|
||||||
|
testTempDirectory = Environment.uniqueTestTempDirectory
|
||||||
|
|
||||||
service = LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.default).make()
|
service = LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.default).make()
|
||||||
|
|
||||||
|
rustBackend = ZcashRustBackend.makeForTests(
|
||||||
|
fsBlockDbRoot: testTempDirectory,
|
||||||
|
networkType: network.networkType
|
||||||
|
)
|
||||||
|
|
||||||
storage = FSCompactBlockRepository(
|
storage = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: ZcashRustBackend.self,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
@ -58,6 +63,8 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
service = nil
|
service = nil
|
||||||
storage = nil
|
storage = nil
|
||||||
downloader = nil
|
downloader = nil
|
||||||
|
rustBackend = nil
|
||||||
|
testTempDirectory = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSmallDownload() async {
|
func testSmallDownload() async {
|
||||||
|
|
|
@ -173,11 +173,13 @@ class RewindRescanTests: XCTestCase {
|
||||||
|
|
||||||
// rewind to birthday
|
// rewind to birthday
|
||||||
let targetHeight: BlockHeight = newChaintTip - 8000
|
let targetHeight: BlockHeight = newChaintTip - 8000
|
||||||
let rewindHeight = await ZcashRustBackend.getNearestRewindHeight(
|
|
||||||
dbData: coordinator.databases.dataDB,
|
do {
|
||||||
height: Int32(targetHeight),
|
_ = try await coordinator.synchronizer.initializer.rustBackend.getNearestRewindHeight(height: Int32(targetHeight))
|
||||||
networkType: network.networkType
|
} catch {
|
||||||
)
|
XCTFail("get nearest height failed error: \(error)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let rewindExpectation = XCTestExpectation(description: "RewindExpectation")
|
let rewindExpectation = XCTestExpectation(description: "RewindExpectation")
|
||||||
|
|
||||||
|
@ -202,11 +204,6 @@ class RewindRescanTests: XCTestCase {
|
||||||
|
|
||||||
wait(for: [rewindExpectation], timeout: 2)
|
wait(for: [rewindExpectation], timeout: 2)
|
||||||
|
|
||||||
guard rewindHeight > 0 else {
|
|
||||||
XCTFail("get nearest height failed error: \(ZcashRustBackend.getLastError() ?? "null")")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// check that the balance is cleared
|
// check that the balance is cleared
|
||||||
var expectedVerifiedBalance = try await coordinator.synchronizer.getShieldedVerifiedBalance()
|
var expectedVerifiedBalance = try await coordinator.synchronizer.getShieldedVerifiedBalance()
|
||||||
XCTAssertEqual(initialVerifiedBalance, expectedVerifiedBalance)
|
XCTAssertEqual(initialVerifiedBalance, expectedVerifiedBalance)
|
||||||
|
|
|
@ -27,6 +27,7 @@ class SynchronizerDarksideTests: XCTestCase {
|
||||||
var foundTransactions: [ZcashTransaction.Overview] = []
|
var foundTransactions: [ZcashTransaction.Overview] = []
|
||||||
var cancellables: [AnyCancellable] = []
|
var cancellables: [AnyCancellable] = []
|
||||||
var idGenerator: MockSyncSessionIDGenerator!
|
var idGenerator: MockSyncSessionIDGenerator!
|
||||||
|
|
||||||
override func setUp() async throws {
|
override func setUp() async throws {
|
||||||
try await super.setUp()
|
try await super.setUp()
|
||||||
idGenerator = MockSyncSessionIDGenerator(ids: [.deadbeef])
|
idGenerator = MockSyncSessionIDGenerator(ids: [.deadbeef])
|
||||||
|
@ -78,7 +79,6 @@ class SynchronizerDarksideTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFoundManyTransactions() async throws {
|
func testFoundManyTransactions() async throws {
|
||||||
|
|
||||||
self.idGenerator.ids = [.deadbeef, .beefbeef, .beefdead]
|
self.idGenerator.ids = [.deadbeef, .beefbeef, .beefdead]
|
||||||
coordinator.synchronizer.eventStream
|
coordinator.synchronizer.eventStream
|
||||||
.map { event in
|
.map { event in
|
||||||
|
@ -143,7 +143,7 @@ class SynchronizerDarksideTests: XCTestCase {
|
||||||
XCTAssertEqual(self.foundTransactions.count, 2)
|
XCTAssertEqual(self.foundTransactions.count, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testLastStates() async throws {
|
func sdfstestLastStates() async throws {
|
||||||
self.idGenerator.ids = [.deadbeef]
|
self.idGenerator.ids = [.deadbeef]
|
||||||
|
|
||||||
var cancellables: [AnyCancellable] = []
|
var cancellables: [AnyCancellable] = []
|
||||||
|
@ -474,7 +474,6 @@ class SynchronizerDarksideTests: XCTestCase {
|
||||||
]
|
]
|
||||||
|
|
||||||
XCTAssertEqual(states, secondBatchOfExpectedStates)
|
XCTAssertEqual(states, secondBatchOfExpectedStates)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSyncAfterWipeWorks() async throws {
|
func testSyncAfterWipeWorks() async throws {
|
||||||
|
|
|
@ -19,16 +19,14 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
let network = DarksideWalletDNetwork()
|
let network = DarksideWalletDNetwork()
|
||||||
let branchID = "2bb40e60"
|
let branchID = "2bb40e60"
|
||||||
let chainName = "main"
|
let chainName = "main"
|
||||||
let testTempDirectory = URL(fileURLWithPath: NSString(
|
|
||||||
string: NSTemporaryDirectory()
|
|
||||||
)
|
|
||||||
.appendingPathComponent("tmp-\(Int.random(in: 0 ... .max))"))
|
|
||||||
|
|
||||||
|
var testTempDirectory: URL!
|
||||||
let testFileManager = FileManager()
|
let testFileManager = FileManager()
|
||||||
|
|
||||||
var initializer: Initializer!
|
var initializer: Initializer!
|
||||||
var processorConfig: CompactBlockProcessor.Configuration!
|
var processorConfig: CompactBlockProcessor.Configuration!
|
||||||
var processor: CompactBlockProcessor!
|
var processor: CompactBlockProcessor!
|
||||||
|
var rustBackend: ZcashRustBackendWelding!
|
||||||
var darksideWalletService: DarksideWalletService!
|
var darksideWalletService: DarksideWalletService!
|
||||||
var downloader: BlockDownloaderServiceImpl!
|
var downloader: BlockDownloaderServiceImpl!
|
||||||
var syncStartedExpect: XCTestExpectation!
|
var syncStartedExpect: XCTestExpectation!
|
||||||
|
@ -42,8 +40,8 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
|
|
||||||
override func setUp() async throws {
|
override func setUp() async throws {
|
||||||
try await super.setUp()
|
try await super.setUp()
|
||||||
|
testTempDirectory = Environment.uniqueTestTempDirectory
|
||||||
try self.testFileManager.createDirectory(at: self.testTempDirectory, withIntermediateDirectories: false)
|
try self.testFileManager.createDirectory(at: testTempDirectory, withIntermediateDirectories: false)
|
||||||
|
|
||||||
await InternalSyncProgress(
|
await InternalSyncProgress(
|
||||||
alias: .default,
|
alias: .default,
|
||||||
|
@ -63,7 +61,6 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
|
|
||||||
waitExpectation = XCTestExpectation(description: "\(self.description) waitExpectation")
|
waitExpectation = XCTestExpectation(description: "\(self.description) waitExpectation")
|
||||||
|
|
||||||
let rustBackend = ZcashRustBackend.self
|
|
||||||
let birthday = Checkpoint.birthday(with: walletBirthday, network: network)
|
let birthday = Checkpoint.birthday(with: walletBirthday, network: network)
|
||||||
|
|
||||||
let pathProvider = DefaultResourceProvider(network: network)
|
let pathProvider = DefaultResourceProvider(network: network)
|
||||||
|
@ -78,27 +75,25 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
network: network
|
network: network
|
||||||
)
|
)
|
||||||
|
|
||||||
|
rustBackend = ZcashRustBackend.makeForTests(
|
||||||
|
dbData: processorConfig.dataDb,
|
||||||
|
fsBlockDbRoot: testTempDirectory,
|
||||||
|
networkType: network.networkType
|
||||||
|
)
|
||||||
|
|
||||||
try? FileManager.default.removeItem(at: processorConfig.fsBlockCacheRoot)
|
try? FileManager.default.removeItem(at: processorConfig.fsBlockCacheRoot)
|
||||||
try? FileManager.default.removeItem(at: processorConfig.dataDb)
|
try? FileManager.default.removeItem(at: processorConfig.dataDb)
|
||||||
|
|
||||||
let dbInit = try await rustBackend.initDataDb(dbData: processorConfig.dataDb, seed: nil, networkType: network.networkType)
|
let dbInit = try await rustBackend.initDataDb(seed: nil)
|
||||||
|
|
||||||
let ufvks = [
|
let derivationTool = DerivationTool(networkType: network.networkType)
|
||||||
try DerivationTool(networkType: network.networkType)
|
let spendingKey = try await derivationTool.deriveUnifiedSpendingKey(seed: Environment.seedBytes, accountIndex: 0)
|
||||||
.deriveUnifiedSpendingKey(seed: Environment.seedBytes, accountIndex: 0)
|
let viewingKey = try await derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
.map {
|
|
||||||
try DerivationTool(networkType: network.networkType)
|
|
||||||
.deriveUnifiedFullViewingKey(from: $0)
|
|
||||||
}
|
|
||||||
]
|
|
||||||
do {
|
do {
|
||||||
try await rustBackend.initAccountsTable(
|
try await rustBackend.initAccountsTable(ufvks: [viewingKey])
|
||||||
dbData: processorConfig.dataDb,
|
|
||||||
ufvks: ufvks,
|
|
||||||
networkType: network.networkType
|
|
||||||
)
|
|
||||||
} catch {
|
} catch {
|
||||||
XCTFail("Failed to init accounts table error: \(String(describing: rustBackend.getLastError()))")
|
XCTFail("Failed to init accounts table error: \(error)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,12 +103,10 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = try await rustBackend.initBlocksTable(
|
_ = try await rustBackend.initBlocksTable(
|
||||||
dbData: processorConfig.dataDb,
|
|
||||||
height: Int32(birthday.height),
|
height: Int32(birthday.height),
|
||||||
hash: birthday.hash,
|
hash: birthday.hash,
|
||||||
time: birthday.time,
|
time: birthday.time,
|
||||||
saplingTree: birthday.saplingTree,
|
saplingTree: birthday.saplingTree
|
||||||
networkType: network.networkType
|
|
||||||
)
|
)
|
||||||
|
|
||||||
let service = DarksideWalletService()
|
let service = DarksideWalletService()
|
||||||
|
@ -136,7 +129,7 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
processor = CompactBlockProcessor(
|
processor = CompactBlockProcessor(
|
||||||
service: service,
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
backend: rustBackend,
|
rustBackend: rustBackend,
|
||||||
config: processorConfig,
|
config: processorConfig,
|
||||||
metrics: SDKMetrics(),
|
metrics: SDKMetrics(),
|
||||||
logger: logger
|
logger: logger
|
||||||
|
@ -163,6 +156,7 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
processor = nil
|
processor = nil
|
||||||
darksideWalletService = nil
|
darksideWalletService = nil
|
||||||
downloader = nil
|
downloader = nil
|
||||||
|
testTempDirectory = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
private func startProcessing() async throws {
|
private func startProcessing() async throws {
|
||||||
|
|
|
@ -15,8 +15,6 @@ import SQLite
|
||||||
class BlockScanTests: XCTestCase {
|
class BlockScanTests: XCTestCase {
|
||||||
var cancelables: [AnyCancellable] = []
|
var cancelables: [AnyCancellable] = []
|
||||||
|
|
||||||
let rustWelding = ZcashRustBackend.self
|
|
||||||
|
|
||||||
var dataDbURL: URL!
|
var dataDbURL: URL!
|
||||||
var spendParamsURL: URL!
|
var spendParamsURL: URL!
|
||||||
var outputParamsURL: URL!
|
var outputParamsURL: URL!
|
||||||
|
@ -27,25 +25,30 @@ class BlockScanTests: XCTestCase {
|
||||||
with: 1386000,
|
with: 1386000,
|
||||||
network: ZcashNetworkBuilder.network(for: .testnet)
|
network: ZcashNetworkBuilder.network(for: .testnet)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var rustBackend: ZcashRustBackendWelding!
|
||||||
|
|
||||||
var network = ZcashNetworkBuilder.network(for: .testnet)
|
var network = ZcashNetworkBuilder.network(for: .testnet)
|
||||||
var blockRepository: BlockRepository!
|
var blockRepository: BlockRepository!
|
||||||
|
var testTempDirectory: URL!
|
||||||
let testTempDirectory = URL(fileURLWithPath: NSString(
|
|
||||||
string: NSTemporaryDirectory()
|
|
||||||
)
|
|
||||||
.appendingPathComponent("tmp-\(Int.random(in: 0 ... .max))"))
|
|
||||||
|
|
||||||
let testFileManager = FileManager()
|
let testFileManager = FileManager()
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
try super.setUpWithError()
|
try super.setUpWithError()
|
||||||
self.dataDbURL = try! __dataDbURL()
|
dataDbURL = try! __dataDbURL()
|
||||||
self.spendParamsURL = try! __spendParamsURL()
|
spendParamsURL = try! __spendParamsURL()
|
||||||
self.outputParamsURL = try! __outputParamsURL()
|
outputParamsURL = try! __outputParamsURL()
|
||||||
|
testTempDirectory = Environment.uniqueTestTempDirectory
|
||||||
|
|
||||||
try self.testFileManager.createDirectory(at: self.testTempDirectory, withIntermediateDirectories: false)
|
try self.testFileManager.createDirectory(at: testTempDirectory, withIntermediateDirectories: false)
|
||||||
|
|
||||||
|
rustBackend = ZcashRustBackend.makeForTests(
|
||||||
|
dbData: dataDbURL,
|
||||||
|
fsBlockDbRoot: testTempDirectory,
|
||||||
|
networkType: network.networkType
|
||||||
|
)
|
||||||
|
|
||||||
deleteDBs()
|
deleteDBs()
|
||||||
}
|
}
|
||||||
|
@ -63,25 +66,23 @@ class BlockScanTests: XCTestCase {
|
||||||
try? testFileManager.removeItem(at: testTempDirectory)
|
try? testFileManager.removeItem(at: testTempDirectory)
|
||||||
cancelables = []
|
cancelables = []
|
||||||
blockRepository = nil
|
blockRepository = nil
|
||||||
|
testTempDirectory = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSingleDownloadAndScan() async throws {
|
func testSingleDownloadAndScan() async throws {
|
||||||
logger = OSLogger(logLevel: .debug)
|
logger = OSLogger(logLevel: .debug)
|
||||||
|
|
||||||
_ = try await rustWelding.initDataDb(dbData: dataDbURL, seed: nil, networkType: network.networkType)
|
_ = try await rustBackend.initDataDb(seed: nil)
|
||||||
|
|
||||||
let endpoint = LightWalletEndpoint(address: "lightwalletd.testnet.electriccoin.co", port: 9067)
|
let endpoint = LightWalletEndpoint(address: "lightwalletd.testnet.electriccoin.co", port: 9067)
|
||||||
let service = LightWalletServiceFactory(endpoint: endpoint).make()
|
let service = LightWalletServiceFactory(endpoint: endpoint).make()
|
||||||
let blockCount = 100
|
let blockCount = 100
|
||||||
let range = network.constants.saplingActivationHeight ... network.constants.saplingActivationHeight + blockCount
|
let range = network.constants.saplingActivationHeight ... network.constants.saplingActivationHeight + blockCount
|
||||||
|
|
||||||
let fsDbRootURL = self.testTempDirectory
|
|
||||||
|
|
||||||
let rustBackend = ZcashRustBackend.self
|
|
||||||
let fsBlockRepository = FSCompactBlockRepository(
|
let fsBlockRepository = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: fsDbRootURL,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: fsDbRootURL,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: rustBackend,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
|
@ -94,7 +95,7 @@ class BlockScanTests: XCTestCase {
|
||||||
|
|
||||||
let processorConfig = CompactBlockProcessor.Configuration(
|
let processorConfig = CompactBlockProcessor.Configuration(
|
||||||
alias: .default,
|
alias: .default,
|
||||||
fsBlockCacheRoot: fsDbRootURL,
|
fsBlockCacheRoot: testTempDirectory,
|
||||||
dataDb: dataDbURL,
|
dataDb: dataDbURL,
|
||||||
spendParamsURL: spendParamsURL,
|
spendParamsURL: spendParamsURL,
|
||||||
outputParamsURL: outputParamsURL,
|
outputParamsURL: outputParamsURL,
|
||||||
|
@ -106,7 +107,7 @@ class BlockScanTests: XCTestCase {
|
||||||
let compactBlockProcessor = CompactBlockProcessor(
|
let compactBlockProcessor = CompactBlockProcessor(
|
||||||
service: service,
|
service: service,
|
||||||
storage: fsBlockRepository,
|
storage: fsBlockRepository,
|
||||||
backend: rustBackend,
|
rustBackend: rustBackend,
|
||||||
config: processorConfig,
|
config: processorConfig,
|
||||||
metrics: SDKMetrics(),
|
metrics: SDKMetrics(),
|
||||||
logger: logger
|
logger: logger
|
||||||
|
@ -139,45 +140,36 @@ class BlockScanTests: XCTestCase {
|
||||||
let metrics = SDKMetrics()
|
let metrics = SDKMetrics()
|
||||||
metrics.enableMetrics()
|
metrics.enableMetrics()
|
||||||
|
|
||||||
guard try await self.rustWelding.initDataDb(dbData: dataDbURL, seed: nil, networkType: network.networkType) == .success else {
|
guard try await rustBackend.initDataDb(seed: nil) == .success else {
|
||||||
XCTFail("Seed should not be required for this test")
|
XCTFail("Seed should not be required for this test")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let derivationTool = DerivationTool(networkType: .testnet)
|
let derivationTool = DerivationTool(networkType: .testnet)
|
||||||
let ufvk = try derivationTool
|
let spendingKey = try await derivationTool.deriveUnifiedSpendingKey(seed: Array(seed.utf8), accountIndex: 0)
|
||||||
.deriveUnifiedSpendingKey(seed: Array(seed.utf8), accountIndex: 0)
|
let viewingKey = try await derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
.map { try derivationTool.deriveUnifiedFullViewingKey(from: $0) }
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try await self.rustWelding.initAccountsTable(
|
try await rustBackend.initAccountsTable(ufvks: [viewingKey])
|
||||||
dbData: self.dataDbURL,
|
|
||||||
ufvks: [ufvk],
|
|
||||||
networkType: network.networkType
|
|
||||||
)
|
|
||||||
} catch {
|
} catch {
|
||||||
XCTFail("failed to init account table. error: \(self.rustWelding.getLastError() ?? "no error found")")
|
XCTFail("failed to init account table. error: \(error)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try await self.rustWelding.initBlocksTable(
|
try await rustBackend.initBlocksTable(
|
||||||
dbData: dataDbURL,
|
|
||||||
height: Int32(walletBirthDay.height),
|
height: Int32(walletBirthDay.height),
|
||||||
hash: walletBirthDay.hash,
|
hash: walletBirthDay.hash,
|
||||||
time: walletBirthDay.time,
|
time: walletBirthDay.time,
|
||||||
saplingTree: walletBirthDay.saplingTree,
|
saplingTree: walletBirthDay.saplingTree
|
||||||
networkType: network.networkType
|
|
||||||
)
|
)
|
||||||
|
|
||||||
let service = LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.eccTestnet).make()
|
let service = LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.eccTestnet).make()
|
||||||
|
|
||||||
let fsDbRootURL = self.testTempDirectory
|
|
||||||
|
|
||||||
let fsBlockRepository = FSCompactBlockRepository(
|
let fsBlockRepository = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: fsDbRootURL,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: fsDbRootURL,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: rustWelding,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: ZcashCompactBlockDescriptor.live,
|
blockDescriptor: ZcashCompactBlockDescriptor.live,
|
||||||
|
@ -189,7 +181,7 @@ class BlockScanTests: XCTestCase {
|
||||||
|
|
||||||
var processorConfig = CompactBlockProcessor.Configuration(
|
var processorConfig = CompactBlockProcessor.Configuration(
|
||||||
alias: .default,
|
alias: .default,
|
||||||
fsBlockCacheRoot: fsDbRootURL,
|
fsBlockCacheRoot: testTempDirectory,
|
||||||
dataDb: dataDbURL,
|
dataDb: dataDbURL,
|
||||||
spendParamsURL: spendParamsURL,
|
spendParamsURL: spendParamsURL,
|
||||||
outputParamsURL: outputParamsURL,
|
outputParamsURL: outputParamsURL,
|
||||||
|
@ -202,7 +194,7 @@ class BlockScanTests: XCTestCase {
|
||||||
let compactBlockProcessor = CompactBlockProcessor(
|
let compactBlockProcessor = CompactBlockProcessor(
|
||||||
service: service,
|
service: service,
|
||||||
storage: fsBlockRepository,
|
storage: fsBlockRepository,
|
||||||
backend: rustWelding,
|
rustBackend: rustBackend,
|
||||||
config: processorConfig,
|
config: processorConfig,
|
||||||
metrics: metrics,
|
metrics: metrics,
|
||||||
logger: logger
|
logger: logger
|
||||||
|
|
|
@ -10,23 +10,24 @@ import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
class BlockStreamingTest: XCTestCase {
|
class BlockStreamingTest: XCTestCase {
|
||||||
let testTempDirectory = URL(fileURLWithPath: NSString(
|
|
||||||
string: NSTemporaryDirectory()
|
|
||||||
)
|
|
||||||
.appendingPathComponent("tmp-\(Int.random(in: 0 ... .max))"))
|
|
||||||
|
|
||||||
let testFileManager = FileManager()
|
let testFileManager = FileManager()
|
||||||
|
var rustBackend: ZcashRustBackendWelding!
|
||||||
|
var testTempDirectory: URL!
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
try super.setUpWithError()
|
try super.setUpWithError()
|
||||||
try self.testFileManager.createDirectory(at: self.testTempDirectory, withIntermediateDirectories: false)
|
testTempDirectory = Environment.uniqueTestTempDirectory
|
||||||
|
try self.testFileManager.createDirectory(at: testTempDirectory, withIntermediateDirectories: false)
|
||||||
|
rustBackend = ZcashRustBackend.makeForTests(fsBlockDbRoot: testTempDirectory, networkType: .testnet)
|
||||||
logger = OSLogger(logLevel: .debug)
|
logger = OSLogger(logLevel: .debug)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
try super.tearDownWithError()
|
try super.tearDownWithError()
|
||||||
|
rustBackend = nil
|
||||||
try? FileManager.default.removeItem(at: __dataDbURL())
|
try? FileManager.default.removeItem(at: __dataDbURL())
|
||||||
try? testFileManager.removeItem(at: testTempDirectory)
|
try? testFileManager.removeItem(at: testTempDirectory)
|
||||||
|
testTempDirectory = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStream() async throws {
|
func testStream() async throws {
|
||||||
|
@ -68,13 +69,11 @@ class BlockStreamingTest: XCTestCase {
|
||||||
)
|
)
|
||||||
let service = LightWalletServiceFactory(endpoint: endpoint).make()
|
let service = LightWalletServiceFactory(endpoint: endpoint).make()
|
||||||
|
|
||||||
let realRustBackend = ZcashRustBackend.self
|
|
||||||
|
|
||||||
let storage = FSCompactBlockRepository(
|
let storage = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: realRustBackend,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
@ -94,7 +93,7 @@ class BlockStreamingTest: XCTestCase {
|
||||||
let compactBlockProcessor = CompactBlockProcessor(
|
let compactBlockProcessor = CompactBlockProcessor(
|
||||||
service: service,
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
backend: realRustBackend,
|
rustBackend: rustBackend,
|
||||||
config: processorConfig,
|
config: processorConfig,
|
||||||
metrics: SDKMetrics(),
|
metrics: SDKMetrics(),
|
||||||
logger: logger
|
logger: logger
|
||||||
|
@ -132,13 +131,11 @@ class BlockStreamingTest: XCTestCase {
|
||||||
)
|
)
|
||||||
let service = LightWalletServiceFactory(endpoint: endpoint).make()
|
let service = LightWalletServiceFactory(endpoint: endpoint).make()
|
||||||
|
|
||||||
let realRustBackend = ZcashRustBackend.self
|
|
||||||
|
|
||||||
let storage = FSCompactBlockRepository(
|
let storage = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: realRustBackend,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
@ -160,7 +157,7 @@ class BlockStreamingTest: XCTestCase {
|
||||||
let compactBlockProcessor = CompactBlockProcessor(
|
let compactBlockProcessor = CompactBlockProcessor(
|
||||||
service: service,
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
backend: realRustBackend,
|
rustBackend: rustBackend,
|
||||||
config: processorConfig,
|
config: processorConfig,
|
||||||
metrics: SDKMetrics(),
|
metrics: SDKMetrics(),
|
||||||
logger: logger
|
logger: logger
|
||||||
|
|
|
@ -12,9 +12,30 @@ import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
class CompactBlockProcessorTests: XCTestCase {
|
class CompactBlockProcessorTests: XCTestCase {
|
||||||
lazy var processorConfig = {
|
var processorConfig: CompactBlockProcessor.Configuration!
|
||||||
|
var cancellables: [AnyCancellable] = []
|
||||||
|
var processorEventHandler: CompactBlockProcessorEventHandler! = CompactBlockProcessorEventHandler()
|
||||||
|
var rustBackend: ZcashRustBackendWelding!
|
||||||
|
var processor: CompactBlockProcessor!
|
||||||
|
var syncStartedExpect: XCTestExpectation!
|
||||||
|
var updatedNotificationExpectation: XCTestExpectation!
|
||||||
|
var stopNotificationExpectation: XCTestExpectation!
|
||||||
|
var finishedNotificationExpectation: XCTestExpectation!
|
||||||
|
let network = ZcashNetworkBuilder.network(for: .testnet)
|
||||||
|
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000
|
||||||
|
|
||||||
|
let testFileManager = FileManager()
|
||||||
|
var testTempDirectory: URL!
|
||||||
|
|
||||||
|
override func setUp() async throws {
|
||||||
|
try await super.setUp()
|
||||||
|
logger = OSLogger(logLevel: .debug)
|
||||||
|
testTempDirectory = Environment.uniqueTestTempDirectory
|
||||||
|
|
||||||
|
try self.testFileManager.createDirectory(at: testTempDirectory, withIntermediateDirectories: false)
|
||||||
|
|
||||||
let pathProvider = DefaultResourceProvider(network: network)
|
let pathProvider = DefaultResourceProvider(network: network)
|
||||||
return CompactBlockProcessor.Configuration(
|
processorConfig = CompactBlockProcessor.Configuration(
|
||||||
alias: .default,
|
alias: .default,
|
||||||
fsBlockCacheRoot: testTempDirectory,
|
fsBlockCacheRoot: testTempDirectory,
|
||||||
dataDb: pathProvider.dataDbURL,
|
dataDb: pathProvider.dataDbURL,
|
||||||
|
@ -24,28 +45,6 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
walletBirthdayProvider: { ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight },
|
walletBirthdayProvider: { ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight },
|
||||||
network: ZcashNetworkBuilder.network(for: .testnet)
|
network: ZcashNetworkBuilder.network(for: .testnet)
|
||||||
)
|
)
|
||||||
}()
|
|
||||||
|
|
||||||
var cancellables: [AnyCancellable] = []
|
|
||||||
var processorEventHandler: CompactBlockProcessorEventHandler! = CompactBlockProcessorEventHandler()
|
|
||||||
var processor: CompactBlockProcessor!
|
|
||||||
var syncStartedExpect: XCTestExpectation!
|
|
||||||
var updatedNotificationExpectation: XCTestExpectation!
|
|
||||||
var stopNotificationExpectation: XCTestExpectation!
|
|
||||||
var finishedNotificationExpectation: XCTestExpectation!
|
|
||||||
let network = ZcashNetworkBuilder.network(for: .testnet)
|
|
||||||
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000
|
|
||||||
let testTempDirectory = URL(fileURLWithPath: NSString(
|
|
||||||
string: NSTemporaryDirectory()
|
|
||||||
)
|
|
||||||
.appendingPathComponent("tmp-\(Int.random(in: 0 ... .max))"))
|
|
||||||
|
|
||||||
let testFileManager = FileManager()
|
|
||||||
|
|
||||||
override func setUp() async throws {
|
|
||||||
try await super.setUp()
|
|
||||||
logger = OSLogger(logLevel: .debug)
|
|
||||||
try self.testFileManager.createDirectory(at: self.testTempDirectory, withIntermediateDirectories: false)
|
|
||||||
|
|
||||||
await InternalSyncProgress(
|
await InternalSyncProgress(
|
||||||
alias: .default,
|
alias: .default,
|
||||||
|
@ -58,7 +57,14 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
latestBlockHeight: mockLatestHeight,
|
latestBlockHeight: mockLatestHeight,
|
||||||
service: liveService
|
service: liveService
|
||||||
)
|
)
|
||||||
let branchID = try ZcashRustBackend.consensusBranchIdFor(height: Int32(mockLatestHeight), networkType: network.networkType)
|
|
||||||
|
rustBackend = ZcashRustBackend.makeForTests(
|
||||||
|
dbData: processorConfig.dataDb,
|
||||||
|
fsBlockDbRoot: processorConfig.fsBlockCacheRoot,
|
||||||
|
networkType: network.networkType
|
||||||
|
)
|
||||||
|
|
||||||
|
let branchID = try rustBackend.consensusBranchIdFor(height: Int32(mockLatestHeight))
|
||||||
service.mockLightDInfo = LightdInfo.with({ info in
|
service.mockLightDInfo = LightdInfo.with({ info in
|
||||||
info.blockHeight = UInt64(mockLatestHeight)
|
info.blockHeight = UInt64(mockLatestHeight)
|
||||||
info.branch = "asdf"
|
info.branch = "asdf"
|
||||||
|
@ -70,13 +76,11 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
})
|
})
|
||||||
|
|
||||||
let realRustBackend = ZcashRustBackend.self
|
|
||||||
|
|
||||||
let storage = FSCompactBlockRepository(
|
let storage = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: processorConfig.fsBlockCacheRoot,
|
fsBlockDbRoot: processorConfig.fsBlockCacheRoot,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: processorConfig.fsBlockCacheRoot,
|
fsBlockDbRoot: processorConfig.fsBlockCacheRoot,
|
||||||
rustBackend: realRustBackend,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
@ -89,13 +93,13 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
processor = CompactBlockProcessor(
|
processor = CompactBlockProcessor(
|
||||||
service: service,
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
backend: realRustBackend,
|
rustBackend: rustBackend,
|
||||||
config: processorConfig,
|
config: processorConfig,
|
||||||
metrics: SDKMetrics(),
|
metrics: SDKMetrics(),
|
||||||
logger: logger
|
logger: logger
|
||||||
)
|
)
|
||||||
|
|
||||||
let dbInit = try await realRustBackend.initDataDb(dbData: processorConfig.dataDb, seed: nil, networkType: .testnet)
|
let dbInit = try await rustBackend.initDataDb(seed: nil)
|
||||||
|
|
||||||
guard case .success = dbInit else {
|
guard case .success = dbInit else {
|
||||||
XCTFail("Failed to initDataDb. Expected `.success` got: \(dbInit)")
|
XCTFail("Failed to initDataDb. Expected `.success` got: \(dbInit)")
|
||||||
|
@ -125,6 +129,8 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
cancellables = []
|
cancellables = []
|
||||||
processor = nil
|
processor = nil
|
||||||
processorEventHandler = nil
|
processorEventHandler = nil
|
||||||
|
rustBackend = nil
|
||||||
|
testTempDirectory = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func processorFailed(event: CompactBlockProcessor.Event) {
|
func processorFailed(event: CompactBlockProcessor.Event) {
|
||||||
|
|
|
@ -12,9 +12,31 @@ import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
class CompactBlockReorgTests: XCTestCase {
|
class CompactBlockReorgTests: XCTestCase {
|
||||||
lazy var processorConfig = {
|
var processorConfig: CompactBlockProcessor.Configuration!
|
||||||
|
let testFileManager = FileManager()
|
||||||
|
var cancellables: [AnyCancellable] = []
|
||||||
|
var processorEventHandler: CompactBlockProcessorEventHandler! = CompactBlockProcessorEventHandler()
|
||||||
|
var rustBackend: ZcashRustBackendWelding!
|
||||||
|
var rustBackendMockHelper: RustBackendMockHelper!
|
||||||
|
var processor: CompactBlockProcessor!
|
||||||
|
var syncStartedExpect: XCTestExpectation!
|
||||||
|
var updatedNotificationExpectation: XCTestExpectation!
|
||||||
|
var stopNotificationExpectation: XCTestExpectation!
|
||||||
|
var finishedNotificationExpectation: XCTestExpectation!
|
||||||
|
var reorgNotificationExpectation: XCTestExpectation!
|
||||||
|
let network = ZcashNetworkBuilder.network(for: .testnet)
|
||||||
|
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000
|
||||||
|
var testTempDirectory: URL!
|
||||||
|
|
||||||
|
override func setUp() async throws {
|
||||||
|
try await super.setUp()
|
||||||
|
logger = OSLogger(logLevel: .debug)
|
||||||
|
testTempDirectory = Environment.uniqueTestTempDirectory
|
||||||
|
|
||||||
|
try self.testFileManager.createDirectory(at: testTempDirectory, withIntermediateDirectories: false)
|
||||||
|
|
||||||
let pathProvider = DefaultResourceProvider(network: network)
|
let pathProvider = DefaultResourceProvider(network: network)
|
||||||
return CompactBlockProcessor.Configuration(
|
processorConfig = CompactBlockProcessor.Configuration(
|
||||||
alias: .default,
|
alias: .default,
|
||||||
fsBlockCacheRoot: testTempDirectory,
|
fsBlockCacheRoot: testTempDirectory,
|
||||||
dataDb: pathProvider.dataDbURL,
|
dataDb: pathProvider.dataDbURL,
|
||||||
|
@ -24,30 +46,6 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
walletBirthdayProvider: { ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight },
|
walletBirthdayProvider: { ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight },
|
||||||
network: ZcashNetworkBuilder.network(for: .testnet)
|
network: ZcashNetworkBuilder.network(for: .testnet)
|
||||||
)
|
)
|
||||||
}()
|
|
||||||
|
|
||||||
let testTempDirectory = URL(fileURLWithPath: NSString(
|
|
||||||
string: NSTemporaryDirectory()
|
|
||||||
)
|
|
||||||
.appendingPathComponent("tmp-\(Int.random(in: 0 ... .max))"))
|
|
||||||
|
|
||||||
let testFileManager = FileManager()
|
|
||||||
var cancellables: [AnyCancellable] = []
|
|
||||||
var processorEventHandler: CompactBlockProcessorEventHandler! = CompactBlockProcessorEventHandler()
|
|
||||||
|
|
||||||
var processor: CompactBlockProcessor!
|
|
||||||
var syncStartedExpect: XCTestExpectation!
|
|
||||||
var updatedNotificationExpectation: XCTestExpectation!
|
|
||||||
var stopNotificationExpectation: XCTestExpectation!
|
|
||||||
var finishedNotificationExpectation: XCTestExpectation!
|
|
||||||
var reorgNotificationExpectation: XCTestExpectation!
|
|
||||||
let network = ZcashNetworkBuilder.network(for: .testnet)
|
|
||||||
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000
|
|
||||||
|
|
||||||
override func setUp() async throws {
|
|
||||||
try await super.setUp()
|
|
||||||
logger = OSLogger(logLevel: .debug)
|
|
||||||
try self.testFileManager.createDirectory(at: self.testTempDirectory, withIntermediateDirectories: false)
|
|
||||||
|
|
||||||
await InternalSyncProgress(
|
await InternalSyncProgress(
|
||||||
alias: .default,
|
alias: .default,
|
||||||
|
@ -60,8 +58,14 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
latestBlockHeight: mockLatestHeight,
|
latestBlockHeight: mockLatestHeight,
|
||||||
service: liveService
|
service: liveService
|
||||||
)
|
)
|
||||||
|
|
||||||
let branchID = try ZcashRustBackend.consensusBranchIdFor(height: Int32(mockLatestHeight), networkType: network.networkType)
|
rustBackend = ZcashRustBackend.makeForTests(
|
||||||
|
dbData: processorConfig.dataDb,
|
||||||
|
fsBlockDbRoot: processorConfig.fsBlockCacheRoot,
|
||||||
|
networkType: network.networkType
|
||||||
|
)
|
||||||
|
|
||||||
|
let branchID = try rustBackend.consensusBranchIdFor(height: Int32(mockLatestHeight))
|
||||||
service.mockLightDInfo = LightdInfo.with { info in
|
service.mockLightDInfo = LightdInfo.with { info in
|
||||||
info.blockHeight = UInt64(mockLatestHeight)
|
info.blockHeight = UInt64(mockLatestHeight)
|
||||||
info.branch = "asdf"
|
info.branch = "asdf"
|
||||||
|
@ -73,13 +77,11 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
let realRustBackend = ZcashRustBackend.self
|
|
||||||
|
|
||||||
let realCache = FSCompactBlockRepository(
|
let realCache = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: processorConfig.fsBlockCacheRoot,
|
fsBlockDbRoot: processorConfig.fsBlockCacheRoot,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: processorConfig.fsBlockCacheRoot,
|
fsBlockDbRoot: processorConfig.fsBlockCacheRoot,
|
||||||
rustBackend: realRustBackend,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
@ -89,21 +91,23 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
|
|
||||||
try await realCache.create()
|
try await realCache.create()
|
||||||
|
|
||||||
let initResult = try await realRustBackend.initDataDb(dbData: processorConfig.dataDb, seed: nil, networkType: .testnet)
|
let initResult = try await rustBackend.initDataDb(seed: nil)
|
||||||
guard case .success = initResult else {
|
guard case .success = initResult else {
|
||||||
XCTFail("initDataDb failed. Expected Success but got .seedRequired")
|
XCTFail("initDataDb failed. Expected Success but got .seedRequired")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let mockBackend = MockRustBackend.self
|
rustBackendMockHelper = await RustBackendMockHelper(
|
||||||
mockBackend.mockValidateCombinedChainFailAfterAttempts = 3
|
rustBackend: rustBackend,
|
||||||
mockBackend.mockValidateCombinedChainKeepFailing = false
|
mockValidateCombinedChainFailAfterAttempts: 3,
|
||||||
mockBackend.mockValidateCombinedChainFailureHeight = self.network.constants.saplingActivationHeight + 320
|
mockValidateCombinedChainKeepFailing: false,
|
||||||
|
mockValidateCombinedChainFailureError: .invalidChain(upperBound: Int32(network.constants.saplingActivationHeight + 320))
|
||||||
|
)
|
||||||
|
|
||||||
processor = CompactBlockProcessor(
|
processor = CompactBlockProcessor(
|
||||||
service: service,
|
service: service,
|
||||||
storage: realCache,
|
storage: realCache,
|
||||||
backend: mockBackend,
|
rustBackend: rustBackendMockHelper.rustBackendMock,
|
||||||
config: processorConfig,
|
config: processorConfig,
|
||||||
metrics: SDKMetrics(),
|
metrics: SDKMetrics(),
|
||||||
logger: logger
|
logger: logger
|
||||||
|
@ -134,6 +138,8 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
cancellables = []
|
cancellables = []
|
||||||
processorEventHandler = nil
|
processorEventHandler = nil
|
||||||
processor = nil
|
processor = nil
|
||||||
|
rustBackend = nil
|
||||||
|
rustBackendMockHelper = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func processorHandledReorg(event: CompactBlockProcessor.Event) {
|
func processorHandledReorg(event: CompactBlockProcessor.Event) {
|
||||||
|
|
|
@ -12,36 +12,31 @@ import SQLite
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
class DownloadTests: XCTestCase {
|
class DownloadTests: XCTestCase {
|
||||||
let testTempDirectory = URL(fileURLWithPath: NSString(
|
|
||||||
string: NSTemporaryDirectory()
|
|
||||||
)
|
|
||||||
.appendingPathComponent("tmp-\(Int.random(in: 0 ... .max))"))
|
|
||||||
|
|
||||||
let testFileManager = FileManager()
|
let testFileManager = FileManager()
|
||||||
|
|
||||||
var network = ZcashNetworkBuilder.network(for: .testnet)
|
var network = ZcashNetworkBuilder.network(for: .testnet)
|
||||||
|
var testTempDirectory: URL!
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
try super.setUpWithError()
|
try super.setUpWithError()
|
||||||
|
testTempDirectory = Environment.uniqueTestTempDirectory
|
||||||
try self.testFileManager.createDirectory(at: self.testTempDirectory, withIntermediateDirectories: false)
|
try self.testFileManager.createDirectory(at: testTempDirectory, withIntermediateDirectories: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
try super.tearDownWithError()
|
try super.tearDownWithError()
|
||||||
try? testFileManager.removeItem(at: testTempDirectory)
|
try? testFileManager.removeItem(at: testTempDirectory)
|
||||||
|
testTempDirectory = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSingleDownload() async throws {
|
func testSingleDownload() async throws {
|
||||||
let service = LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.eccTestnet).make()
|
let service = LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.eccTestnet).make()
|
||||||
|
let rustBackend = ZcashRustBackend.makeForTests(fsBlockDbRoot: testTempDirectory, networkType: network.networkType)
|
||||||
let realRustBackend = ZcashRustBackend.self
|
|
||||||
|
|
||||||
let storage = FSCompactBlockRepository(
|
let storage = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: realRustBackend,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
@ -63,7 +58,7 @@ class DownloadTests: XCTestCase {
|
||||||
let compactBlockProcessor = CompactBlockProcessor(
|
let compactBlockProcessor = CompactBlockProcessor(
|
||||||
service: service,
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
backend: realRustBackend,
|
rustBackend: rustBackend,
|
||||||
config: processorConfig,
|
config: processorConfig,
|
||||||
metrics: SDKMetrics(),
|
metrics: SDKMetrics(),
|
||||||
logger: logger
|
logger: logger
|
||||||
|
|
|
@ -10,21 +10,22 @@ import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
class BlockBatchValidationTests: XCTestCase {
|
class BlockBatchValidationTests: XCTestCase {
|
||||||
let testTempDirectory = URL(fileURLWithPath: NSString(
|
|
||||||
string: NSTemporaryDirectory()
|
|
||||||
)
|
|
||||||
.appendingPathComponent("tmp-\(Int.random(in: 0 ... .max))"))
|
|
||||||
|
|
||||||
let testFileManager = FileManager()
|
let testFileManager = FileManager()
|
||||||
|
var rustBackend: ZcashRustBackendWelding!
|
||||||
|
var testTempDirectory: URL!
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
try super.setUpWithError()
|
try super.setUpWithError()
|
||||||
try self.testFileManager.createDirectory(at: self.testTempDirectory, withIntermediateDirectories: false)
|
testTempDirectory = Environment.uniqueTestTempDirectory
|
||||||
|
try self.testFileManager.createDirectory(at: testTempDirectory, withIntermediateDirectories: false)
|
||||||
|
rustBackend = ZcashRustBackend.makeForTests(fsBlockDbRoot: testTempDirectory, networkType: .testnet)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
try super.tearDownWithError()
|
try super.tearDownWithError()
|
||||||
try? testFileManager.removeItem(at: testTempDirectory)
|
try? testFileManager.removeItem(at: testTempDirectory)
|
||||||
|
rustBackend = nil
|
||||||
|
testTempDirectory = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testBranchIdFailure() async throws {
|
func testBranchIdFailure() async throws {
|
||||||
|
@ -34,13 +35,11 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
service: LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.default).make()
|
service: LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.default).make()
|
||||||
)
|
)
|
||||||
|
|
||||||
let realRustBackend = ZcashRustBackend.self
|
|
||||||
|
|
||||||
let storage = FSCompactBlockRepository(
|
let storage = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: realRustBackend,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
@ -76,14 +75,13 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
info.consensusBranchID = "d34db33f"
|
info.consensusBranchID = "d34db33f"
|
||||||
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockBackend = await RustBackendMockHelper(rustBackend: rustBackend, consensusBranchID: Int32(0xd34d))
|
||||||
mockRust.consensusBranchID = Int32(0xd34d)
|
|
||||||
|
|
||||||
let compactBlockProcessor = CompactBlockProcessor(
|
let compactBlockProcessor = CompactBlockProcessor(
|
||||||
service: service,
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
backend: mockRust,
|
rustBackend: mockBackend.rustBackendMock,
|
||||||
config: config,
|
config: config,
|
||||||
metrics: SDKMetrics(),
|
metrics: SDKMetrics(),
|
||||||
logger: logger
|
logger: logger
|
||||||
|
@ -109,13 +107,11 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
service: LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.default).make()
|
service: LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.default).make()
|
||||||
)
|
)
|
||||||
|
|
||||||
let realRustBackend = ZcashRustBackend.self
|
|
||||||
|
|
||||||
let storage = FSCompactBlockRepository(
|
let storage = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: realRustBackend,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
@ -151,14 +147,13 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
|
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockBackend = await RustBackendMockHelper(rustBackend: rustBackend, consensusBranchID: 0xd34db4d)
|
||||||
mockRust.consensusBranchID = 0xd34db4d
|
|
||||||
|
|
||||||
let compactBlockProcessor = CompactBlockProcessor(
|
let compactBlockProcessor = CompactBlockProcessor(
|
||||||
service: service,
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
backend: mockRust,
|
rustBackend: mockBackend.rustBackendMock,
|
||||||
config: config,
|
config: config,
|
||||||
metrics: SDKMetrics(),
|
metrics: SDKMetrics(),
|
||||||
logger: logger
|
logger: logger
|
||||||
|
@ -184,13 +179,11 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
service: LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.default).make()
|
service: LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.default).make()
|
||||||
)
|
)
|
||||||
|
|
||||||
let realRustBackend = ZcashRustBackend.self
|
|
||||||
|
|
||||||
let storage = FSCompactBlockRepository(
|
let storage = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: realRustBackend,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
@ -227,13 +220,12 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
|
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockBackend = await RustBackendMockHelper(rustBackend: rustBackend, consensusBranchID: 0xd34db4d)
|
||||||
mockRust.consensusBranchID = 0xd34db4d
|
|
||||||
|
|
||||||
let compactBlockProcessor = CompactBlockProcessor(
|
let compactBlockProcessor = CompactBlockProcessor(
|
||||||
service: service,
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
backend: mockRust,
|
rustBackend: mockBackend.rustBackendMock,
|
||||||
config: config,
|
config: config,
|
||||||
metrics: SDKMetrics(),
|
metrics: SDKMetrics(),
|
||||||
logger: logger
|
logger: logger
|
||||||
|
@ -259,13 +251,11 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
service: LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.default).make()
|
service: LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.default).make()
|
||||||
)
|
)
|
||||||
|
|
||||||
let realRustBackend = ZcashRustBackend.self
|
|
||||||
|
|
||||||
let storage = FSCompactBlockRepository(
|
let storage = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: realRustBackend,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
@ -303,13 +293,12 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
|
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockBackend = await RustBackendMockHelper(rustBackend: rustBackend, consensusBranchID: 0xd34db4d)
|
||||||
mockRust.consensusBranchID = 0xd34db4d
|
|
||||||
|
|
||||||
let compactBlockProcessor = CompactBlockProcessor(
|
let compactBlockProcessor = CompactBlockProcessor(
|
||||||
service: service,
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
backend: mockRust,
|
rustBackend: mockBackend.rustBackendMock,
|
||||||
config: config,
|
config: config,
|
||||||
metrics: SDKMetrics(),
|
metrics: SDKMetrics(),
|
||||||
logger: logger
|
logger: logger
|
||||||
|
@ -381,9 +370,8 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
|
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockBackend = await RustBackendMockHelper(rustBackend: rustBackend, consensusBranchID: 0xd34db4d)
|
||||||
mockRust.consensusBranchID = 0xd34db4d
|
|
||||||
|
|
||||||
var nextBatch: CompactBlockProcessor.NextState?
|
var nextBatch: CompactBlockProcessor.NextState?
|
||||||
do {
|
do {
|
||||||
|
@ -392,7 +380,7 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
downloaderService: downloaderService,
|
downloaderService: downloaderService,
|
||||||
transactionRepository: transactionRepository,
|
transactionRepository: transactionRepository,
|
||||||
config: config,
|
config: config,
|
||||||
rustBackend: mockRust,
|
rustBackend: mockBackend.rustBackendMock,
|
||||||
internalSyncProgress: InternalSyncProgress(
|
internalSyncProgress: InternalSyncProgress(
|
||||||
alias: .default,
|
alias: .default,
|
||||||
storage: InternalSyncProgressMemoryStorage(),
|
storage: InternalSyncProgressMemoryStorage(),
|
||||||
|
@ -479,8 +467,7 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
|
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockBackend = await RustBackendMockHelper(rustBackend: rustBackend, consensusBranchID: 0xd34db4d)
|
||||||
mockRust.consensusBranchID = 0xd34db4d
|
|
||||||
|
|
||||||
var nextBatch: CompactBlockProcessor.NextState?
|
var nextBatch: CompactBlockProcessor.NextState?
|
||||||
do {
|
do {
|
||||||
|
@ -489,7 +476,7 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
downloaderService: downloaderService,
|
downloaderService: downloaderService,
|
||||||
transactionRepository: transactionRepository,
|
transactionRepository: transactionRepository,
|
||||||
config: config,
|
config: config,
|
||||||
rustBackend: mockRust,
|
rustBackend: mockBackend.rustBackendMock,
|
||||||
internalSyncProgress: InternalSyncProgress(
|
internalSyncProgress: InternalSyncProgress(
|
||||||
alias: .default,
|
alias: .default,
|
||||||
storage: InternalSyncProgressMemoryStorage(),
|
storage: InternalSyncProgressMemoryStorage(),
|
||||||
|
@ -573,8 +560,7 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
|
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockBackend = await RustBackendMockHelper(rustBackend: rustBackend, consensusBranchID: 0xd34db4d)
|
||||||
mockRust.consensusBranchID = 0xd34db4d
|
|
||||||
|
|
||||||
var nextBatch: CompactBlockProcessor.NextState?
|
var nextBatch: CompactBlockProcessor.NextState?
|
||||||
do {
|
do {
|
||||||
|
@ -583,7 +569,7 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
downloaderService: downloaderService,
|
downloaderService: downloaderService,
|
||||||
transactionRepository: transactionRepository,
|
transactionRepository: transactionRepository,
|
||||||
config: config,
|
config: config,
|
||||||
rustBackend: mockRust,
|
rustBackend: mockBackend.rustBackendMock,
|
||||||
internalSyncProgress: internalSyncProgress
|
internalSyncProgress: internalSyncProgress
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import XCTest
|
||||||
extension String: Error { }
|
extension String: Error { }
|
||||||
|
|
||||||
class ClosureSynchronizerOfflineTests: XCTestCase {
|
class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
var data: AlternativeSynchronizerAPITestsData!
|
var data: TestsData!
|
||||||
|
|
||||||
var cancellables: [AnyCancellable] = []
|
var cancellables: [AnyCancellable] = []
|
||||||
var synchronizerMock: SynchronizerMock!
|
var synchronizerMock: SynchronizerMock!
|
||||||
|
@ -22,7 +22,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
try super.setUpWithError()
|
try super.setUpWithError()
|
||||||
data = AlternativeSynchronizerAPITestsData()
|
data = TestsData(networkType: .testnet)
|
||||||
synchronizerMock = SynchronizerMock()
|
synchronizerMock = SynchronizerMock()
|
||||||
synchronizer = ClosureSDKSynchronizer(synchronizer: synchronizerMock)
|
synchronizer = ClosureSDKSynchronizer(synchronizer: synchronizerMock)
|
||||||
cancellables = []
|
cancellables = []
|
||||||
|
@ -114,17 +114,18 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
XCTAssertEqual(synchronizer.connectionState, .reconnecting)
|
XCTAssertEqual(synchronizer.connectionState, .reconnecting)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPrepareSucceed() throws {
|
func testPrepareSucceed() async throws {
|
||||||
synchronizerMock.prepareWithSeedViewingKeysWalletBirthdayClosure = { receivedSeed, receivedViewingKeys, receivedWalletBirthday in
|
let mockedViewingKey = await data.viewingKey
|
||||||
|
synchronizerMock.prepareWithViewingKeysWalletBirthdayClosure = { receivedSeed, receivedViewingKeys, receivedWalletBirthday in
|
||||||
XCTAssertEqual(receivedSeed, self.data.seed)
|
XCTAssertEqual(receivedSeed, self.data.seed)
|
||||||
XCTAssertEqual(receivedViewingKeys, [self.data.viewingKey])
|
XCTAssertEqual(receivedViewingKeys, [mockedViewingKey])
|
||||||
XCTAssertEqual(receivedWalletBirthday, self.data.birthday)
|
XCTAssertEqual(receivedWalletBirthday, self.data.birthday)
|
||||||
return .success
|
return .success
|
||||||
}
|
}
|
||||||
|
|
||||||
let expectation = XCTestExpectation()
|
let expectation = XCTestExpectation()
|
||||||
|
|
||||||
synchronizer.prepare(with: data.seed, viewingKeys: [data.viewingKey], walletBirthday: data.birthday) { result in
|
synchronizer.prepare(with: data.seed, viewingKeys: [mockedViewingKey], walletBirthday: data.birthday) { result in
|
||||||
switch result {
|
switch result {
|
||||||
case let .success(status):
|
case let .success(status):
|
||||||
XCTAssertEqual(status, .success)
|
XCTAssertEqual(status, .success)
|
||||||
|
@ -137,14 +138,15 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
wait(for: [expectation], timeout: 0.5)
|
wait(for: [expectation], timeout: 0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPrepareThrowsError() throws {
|
func testPrepareThrowsError() async throws {
|
||||||
synchronizerMock.prepareWithSeedViewingKeysWalletBirthdayClosure = { _, _, _ in
|
let mockedViewingKey = await data.viewingKey
|
||||||
|
synchronizerMock.prepareWithViewingKeysWalletBirthdayClosure = { _, _, _ in
|
||||||
throw "Some error"
|
throw "Some error"
|
||||||
}
|
}
|
||||||
|
|
||||||
let expectation = XCTestExpectation()
|
let expectation = XCTestExpectation()
|
||||||
|
|
||||||
synchronizer.prepare(with: data.seed, viewingKeys: [data.viewingKey], walletBirthday: data.birthday) { result in
|
synchronizer.prepare(with: data.seed, viewingKeys: [mockedViewingKey], walletBirthday: data.birthday) { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .success:
|
case .success:
|
||||||
XCTFail("Error should be thrown.")
|
XCTFail("Error should be thrown.")
|
||||||
|
@ -324,14 +326,15 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
wait(for: [expectation], timeout: 0.5)
|
wait(for: [expectation], timeout: 0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSendToAddressSucceed() throws {
|
func testSendToAddressSucceed() async throws {
|
||||||
let amount = Zatoshi(100)
|
let amount = Zatoshi(100)
|
||||||
let recipient: Recipient = .transparent(data.transparentAddress)
|
let recipient: Recipient = .transparent(data.transparentAddress)
|
||||||
let memo: Memo = .text(try MemoText("Some message"))
|
let memo: Memo = .text(try MemoText("Some message"))
|
||||||
|
let mockedSpendingKey = await data.spendingKey
|
||||||
|
|
||||||
synchronizerMock
|
synchronizerMock
|
||||||
.sendToAddressSpendingKeyZatoshiToAddressMemoClosure = { receivedSpendingKey, receivedZatoshi, receivedToAddress, receivedMemo in
|
.sendToAddressSpendingKeyZatoshiToAddressMemoClosure = { receivedSpendingKey, receivedZatoshi, receivedToAddress, receivedMemo in
|
||||||
XCTAssertEqual(receivedSpendingKey, self.data.spendingKey)
|
XCTAssertEqual(receivedSpendingKey, mockedSpendingKey)
|
||||||
XCTAssertEqual(receivedZatoshi, amount)
|
XCTAssertEqual(receivedZatoshi, amount)
|
||||||
XCTAssertEqual(receivedToAddress, recipient)
|
XCTAssertEqual(receivedToAddress, recipient)
|
||||||
XCTAssertEqual(receivedMemo, memo)
|
XCTAssertEqual(receivedMemo, memo)
|
||||||
|
@ -340,7 +343,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
|
|
||||||
let expectation = XCTestExpectation()
|
let expectation = XCTestExpectation()
|
||||||
|
|
||||||
synchronizer.sendToAddress(spendingKey: data.spendingKey, zatoshi: amount, toAddress: recipient, memo: memo) { result in
|
synchronizer.sendToAddress(spendingKey: mockedSpendingKey, zatoshi: amount, toAddress: recipient, memo: memo) { result in
|
||||||
switch result {
|
switch result {
|
||||||
case let .success(receivedEntity):
|
case let .success(receivedEntity):
|
||||||
XCTAssertEqual(receivedEntity.recipient, self.data.pendingTransactionEntity.recipient)
|
XCTAssertEqual(receivedEntity.recipient, self.data.pendingTransactionEntity.recipient)
|
||||||
|
@ -353,10 +356,11 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
wait(for: [expectation], timeout: 0.5)
|
wait(for: [expectation], timeout: 0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSendToAddressThrowsError() throws {
|
func testSendToAddressThrowsError() async throws {
|
||||||
let amount = Zatoshi(100)
|
let amount = Zatoshi(100)
|
||||||
let recipient: Recipient = .transparent(data.transparentAddress)
|
let recipient: Recipient = .transparent(data.transparentAddress)
|
||||||
let memo: Memo = .text(try MemoText("Some message"))
|
let memo: Memo = .text(try MemoText("Some message"))
|
||||||
|
let mockedSpendingKey = await data.spendingKey
|
||||||
|
|
||||||
synchronizerMock.sendToAddressSpendingKeyZatoshiToAddressMemoClosure = { _, _, _, _ in
|
synchronizerMock.sendToAddressSpendingKeyZatoshiToAddressMemoClosure = { _, _, _, _ in
|
||||||
throw "Some error"
|
throw "Some error"
|
||||||
|
@ -364,7 +368,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
|
|
||||||
let expectation = XCTestExpectation()
|
let expectation = XCTestExpectation()
|
||||||
|
|
||||||
synchronizer.sendToAddress(spendingKey: data.spendingKey, zatoshi: amount, toAddress: recipient, memo: memo) { result in
|
synchronizer.sendToAddress(spendingKey: mockedSpendingKey, zatoshi: amount, toAddress: recipient, memo: memo) { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .success:
|
case .success:
|
||||||
XCTFail("Error should be thrown.")
|
XCTFail("Error should be thrown.")
|
||||||
|
@ -376,12 +380,13 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
wait(for: [expectation], timeout: 0.5)
|
wait(for: [expectation], timeout: 0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testShieldFundsSucceed() throws {
|
func testShieldFundsSucceed() async throws {
|
||||||
let memo: Memo = .text(try MemoText("Some message"))
|
let memo: Memo = .text(try MemoText("Some message"))
|
||||||
let shieldingThreshold = Zatoshi(1)
|
let shieldingThreshold = Zatoshi(1)
|
||||||
|
let mockedSpendingKey = await data.spendingKey
|
||||||
|
|
||||||
synchronizerMock.shieldFundsSpendingKeyMemoShieldingThresholdClosure = { receivedSpendingKey, receivedMemo, receivedShieldingThreshold in
|
synchronizerMock.shieldFundsSpendingKeyMemoShieldingThresholdClosure = { receivedSpendingKey, receivedMemo, receivedShieldingThreshold in
|
||||||
XCTAssertEqual(receivedSpendingKey, self.data.spendingKey)
|
XCTAssertEqual(receivedSpendingKey, mockedSpendingKey)
|
||||||
XCTAssertEqual(receivedMemo, memo)
|
XCTAssertEqual(receivedMemo, memo)
|
||||||
XCTAssertEqual(receivedShieldingThreshold, shieldingThreshold)
|
XCTAssertEqual(receivedShieldingThreshold, shieldingThreshold)
|
||||||
return self.data.pendingTransactionEntity
|
return self.data.pendingTransactionEntity
|
||||||
|
@ -389,7 +394,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
|
|
||||||
let expectation = XCTestExpectation()
|
let expectation = XCTestExpectation()
|
||||||
|
|
||||||
synchronizer.shieldFunds(spendingKey: data.spendingKey, memo: memo, shieldingThreshold: shieldingThreshold) { result in
|
synchronizer.shieldFunds(spendingKey: mockedSpendingKey, memo: memo, shieldingThreshold: shieldingThreshold) { result in
|
||||||
switch result {
|
switch result {
|
||||||
case let .success(receivedEntity):
|
case let .success(receivedEntity):
|
||||||
XCTAssertEqual(receivedEntity.recipient, self.data.pendingTransactionEntity.recipient)
|
XCTAssertEqual(receivedEntity.recipient, self.data.pendingTransactionEntity.recipient)
|
||||||
|
@ -402,9 +407,10 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
wait(for: [expectation], timeout: 0.5)
|
wait(for: [expectation], timeout: 0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testShieldFundsThrowsError() throws {
|
func testShieldFundsThrowsError() async throws {
|
||||||
let memo: Memo = .text(try MemoText("Some message"))
|
let memo: Memo = .text(try MemoText("Some message"))
|
||||||
let shieldingThreshold = Zatoshi(1)
|
let shieldingThreshold = Zatoshi(1)
|
||||||
|
let mockedSpendingKey = await data.spendingKey
|
||||||
|
|
||||||
synchronizerMock.shieldFundsSpendingKeyMemoShieldingThresholdClosure = { _, _, _ in
|
synchronizerMock.shieldFundsSpendingKeyMemoShieldingThresholdClosure = { _, _, _ in
|
||||||
throw "Some error"
|
throw "Some error"
|
||||||
|
@ -412,7 +418,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
|
|
||||||
let expectation = XCTestExpectation()
|
let expectation = XCTestExpectation()
|
||||||
|
|
||||||
synchronizer.shieldFunds(spendingKey: data.spendingKey, memo: memo, shieldingThreshold: shieldingThreshold) { result in
|
synchronizer.shieldFunds(spendingKey: mockedSpendingKey, memo: memo, shieldingThreshold: shieldingThreshold) { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .success:
|
case .success:
|
||||||
XCTFail("Error should be thrown.")
|
XCTFail("Error should be thrown.")
|
||||||
|
@ -499,7 +505,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
func testGetMemosForClearedTransactionSucceed() throws {
|
func testGetMemosForClearedTransactionSucceed() throws {
|
||||||
let memo: Memo = .text(try MemoText("Some message"))
|
let memo: Memo = .text(try MemoText("Some message"))
|
||||||
|
|
||||||
synchronizerMock.getMemosForTransactionClosure = { receivedTransaction in
|
synchronizerMock.getMemosForClearedTransactionClosure = { receivedTransaction in
|
||||||
XCTAssertEqual(receivedTransaction.id, self.data.clearedTransaction.id)
|
XCTAssertEqual(receivedTransaction.id, self.data.clearedTransaction.id)
|
||||||
return [memo]
|
return [memo]
|
||||||
}
|
}
|
||||||
|
@ -521,7 +527,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGetMemosForClearedTransactionThrowsError() {
|
func testGetMemosForClearedTransactionThrowsError() {
|
||||||
synchronizerMock.getMemosForTransactionClosure = { _ in
|
synchronizerMock.getMemosForClearedTransactionClosure = { _ in
|
||||||
throw "Some error"
|
throw "Some error"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,7 +670,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAllConfirmedTransactionsSucceed() throws {
|
func testAllConfirmedTransactionsSucceed() throws {
|
||||||
synchronizerMock.allConfirmedTransactionsFromTransactionClosure = { receivedTransaction, limit in
|
synchronizerMock.allConfirmedTransactionsFromLimitClosure = { receivedTransaction, limit in
|
||||||
XCTAssertEqual(receivedTransaction.id, self.data.clearedTransaction.id)
|
XCTAssertEqual(receivedTransaction.id, self.data.clearedTransaction.id)
|
||||||
XCTAssertEqual(limit, 3)
|
XCTAssertEqual(limit, 3)
|
||||||
return [self.data.clearedTransaction]
|
return [self.data.clearedTransaction]
|
||||||
|
@ -687,7 +693,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAllConfirmedTransactionsThrowsError() throws {
|
func testAllConfirmedTransactionsThrowsError() throws {
|
||||||
synchronizerMock.allConfirmedTransactionsFromTransactionClosure = { _, _ in
|
synchronizerMock.allConfirmedTransactionsFromLimitClosure = { _, _ in
|
||||||
throw "Some error"
|
throw "Some error"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -747,7 +753,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
let skippedEntity = UnspentTransactionOutputEntityMock(address: "addr2", txid: Data(), index: 1, script: Data(), valueZat: 2, height: 3)
|
let skippedEntity = UnspentTransactionOutputEntityMock(address: "addr2", txid: Data(), index: 1, script: Data(), valueZat: 2, height: 3)
|
||||||
let refreshedUTXO = (inserted: [insertedEntity], skipped: [skippedEntity])
|
let refreshedUTXO = (inserted: [insertedEntity], skipped: [skippedEntity])
|
||||||
|
|
||||||
synchronizerMock.refreshUTXOsAddressFromHeightClosure = { receivedAddress, receivedFromHeight in
|
synchronizerMock.refreshUTXOsAddressFromClosure = { receivedAddress, receivedFromHeight in
|
||||||
XCTAssertEqual(receivedAddress, self.data.transparentAddress)
|
XCTAssertEqual(receivedAddress, self.data.transparentAddress)
|
||||||
XCTAssertEqual(receivedFromHeight, 121000)
|
XCTAssertEqual(receivedFromHeight, 121000)
|
||||||
return refreshedUTXO
|
return refreshedUTXO
|
||||||
|
@ -770,7 +776,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRefreshUTXOsThrowsError() {
|
func testRefreshUTXOsThrowsError() {
|
||||||
synchronizerMock.refreshUTXOsAddressFromHeightClosure = { _, _ in
|
synchronizerMock.refreshUTXOsAddressFromClosure = { _, _ in
|
||||||
throw "Some error"
|
throw "Some error"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -911,7 +917,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRewindSucceed() {
|
func testRewindSucceed() {
|
||||||
synchronizerMock.rewindPolicyClosure = { receivedPolicy in
|
synchronizerMock.rewindClosure = { receivedPolicy in
|
||||||
if case .quick = receivedPolicy {
|
if case .quick = receivedPolicy {
|
||||||
} else {
|
} else {
|
||||||
XCTFail("Unexpected policy \(receivedPolicy)")
|
XCTFail("Unexpected policy \(receivedPolicy)")
|
||||||
|
@ -940,7 +946,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRewindThrowsError() {
|
func testRewindThrowsError() {
|
||||||
synchronizerMock.rewindPolicyClosure = { _ in
|
synchronizerMock.rewindClosure = { _ in
|
||||||
return Fail(error: "some error").eraseToAnyPublisher()
|
return Fail(error: "some error").eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
class CombineSynchronizerOfflineTests: XCTestCase {
|
class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
var data: AlternativeSynchronizerAPITestsData!
|
var data: TestsData!
|
||||||
|
|
||||||
var cancellables: [AnyCancellable] = []
|
var cancellables: [AnyCancellable] = []
|
||||||
var synchronizerMock: SynchronizerMock!
|
var synchronizerMock: SynchronizerMock!
|
||||||
|
@ -20,7 +20,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
try super.setUpWithError()
|
try super.setUpWithError()
|
||||||
data = AlternativeSynchronizerAPITestsData()
|
data = TestsData(networkType: .testnet)
|
||||||
synchronizerMock = SynchronizerMock()
|
synchronizerMock = SynchronizerMock()
|
||||||
synchronizer = CombineSDKSynchronizer(synchronizer: synchronizerMock)
|
synchronizer = CombineSDKSynchronizer(synchronizer: synchronizerMock)
|
||||||
cancellables = []
|
cancellables = []
|
||||||
|
@ -112,17 +112,18 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
XCTAssertEqual(synchronizer.connectionState, .reconnecting)
|
XCTAssertEqual(synchronizer.connectionState, .reconnecting)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPrepareSucceed() throws {
|
func testPrepareSucceed() async throws {
|
||||||
synchronizerMock.prepareWithSeedViewingKeysWalletBirthdayClosure = { receivedSeed, receivedViewingKeys, receivedWalletBirthday in
|
let mockedViewingKey = await self.data.viewingKey
|
||||||
|
synchronizerMock.prepareWithViewingKeysWalletBirthdayClosure = { receivedSeed, receivedViewingKeys, receivedWalletBirthday in
|
||||||
XCTAssertEqual(receivedSeed, self.data.seed)
|
XCTAssertEqual(receivedSeed, self.data.seed)
|
||||||
XCTAssertEqual(receivedViewingKeys, [self.data.viewingKey])
|
XCTAssertEqual(receivedViewingKeys, [mockedViewingKey])
|
||||||
XCTAssertEqual(receivedWalletBirthday, self.data.birthday)
|
XCTAssertEqual(receivedWalletBirthday, self.data.birthday)
|
||||||
return .success
|
return .success
|
||||||
}
|
}
|
||||||
|
|
||||||
let expectation = XCTestExpectation()
|
let expectation = XCTestExpectation()
|
||||||
|
|
||||||
synchronizer.prepare(with: data.seed, viewingKeys: [data.viewingKey], walletBirthday: data.birthday)
|
synchronizer.prepare(with: data.seed, viewingKeys: [mockedViewingKey], walletBirthday: data.birthday)
|
||||||
.sink(
|
.sink(
|
||||||
receiveCompletion: { result in
|
receiveCompletion: { result in
|
||||||
switch result {
|
switch result {
|
||||||
|
@ -141,14 +142,15 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
wait(for: [expectation], timeout: 0.5)
|
wait(for: [expectation], timeout: 0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPrepareThrowsError() throws {
|
func testPrepareThrowsError() async throws {
|
||||||
synchronizerMock.prepareWithSeedViewingKeysWalletBirthdayClosure = { _, _, _ in
|
let mockedViewingKey = await self.data.viewingKey
|
||||||
|
synchronizerMock.prepareWithViewingKeysWalletBirthdayClosure = { _, _, _ in
|
||||||
throw "Some error"
|
throw "Some error"
|
||||||
}
|
}
|
||||||
|
|
||||||
let expectation = XCTestExpectation()
|
let expectation = XCTestExpectation()
|
||||||
|
|
||||||
synchronizer.prepare(with: data.seed, viewingKeys: [data.viewingKey], walletBirthday: data.birthday)
|
synchronizer.prepare(with: data.seed, viewingKeys: [mockedViewingKey], walletBirthday: data.birthday)
|
||||||
.sink(
|
.sink(
|
||||||
receiveCompletion: { result in
|
receiveCompletion: { result in
|
||||||
switch result {
|
switch result {
|
||||||
|
@ -329,14 +331,15 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
wait(for: [expectation], timeout: 0.5)
|
wait(for: [expectation], timeout: 0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSendToAddressSucceed() throws {
|
func testSendToAddressSucceed() async throws {
|
||||||
let amount = Zatoshi(100)
|
let amount = Zatoshi(100)
|
||||||
let recipient: Recipient = .transparent(data.transparentAddress)
|
let recipient: Recipient = .transparent(data.transparentAddress)
|
||||||
let memo: Memo = .text(try MemoText("Some message"))
|
let memo: Memo = .text(try MemoText("Some message"))
|
||||||
|
let mockedSpendingKey = await data.spendingKey
|
||||||
|
|
||||||
synchronizerMock
|
synchronizerMock
|
||||||
.sendToAddressSpendingKeyZatoshiToAddressMemoClosure = { receivedSpendingKey, receivedZatoshi, receivedToAddress, receivedMemo in
|
.sendToAddressSpendingKeyZatoshiToAddressMemoClosure = { receivedSpendingKey, receivedZatoshi, receivedToAddress, receivedMemo in
|
||||||
XCTAssertEqual(receivedSpendingKey, self.data.spendingKey)
|
XCTAssertEqual(receivedSpendingKey, mockedSpendingKey)
|
||||||
XCTAssertEqual(receivedZatoshi, amount)
|
XCTAssertEqual(receivedZatoshi, amount)
|
||||||
XCTAssertEqual(receivedToAddress, recipient)
|
XCTAssertEqual(receivedToAddress, recipient)
|
||||||
XCTAssertEqual(receivedMemo, memo)
|
XCTAssertEqual(receivedMemo, memo)
|
||||||
|
@ -345,7 +348,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
|
|
||||||
let expectation = XCTestExpectation()
|
let expectation = XCTestExpectation()
|
||||||
|
|
||||||
synchronizer.sendToAddress(spendingKey: data.spendingKey, zatoshi: amount, toAddress: recipient, memo: memo)
|
synchronizer.sendToAddress(spendingKey: mockedSpendingKey, zatoshi: amount, toAddress: recipient, memo: memo)
|
||||||
.sink(
|
.sink(
|
||||||
receiveCompletion: { result in
|
receiveCompletion: { result in
|
||||||
switch result {
|
switch result {
|
||||||
|
@ -364,10 +367,11 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
wait(for: [expectation], timeout: 0.5)
|
wait(for: [expectation], timeout: 0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSendToAddressThrowsError() throws {
|
func testSendToAddressThrowsError() async throws {
|
||||||
let amount = Zatoshi(100)
|
let amount = Zatoshi(100)
|
||||||
let recipient: Recipient = .transparent(data.transparentAddress)
|
let recipient: Recipient = .transparent(data.transparentAddress)
|
||||||
let memo: Memo = .text(try MemoText("Some message"))
|
let memo: Memo = .text(try MemoText("Some message"))
|
||||||
|
let mockedSpendingKey = await data.spendingKey
|
||||||
|
|
||||||
synchronizerMock.sendToAddressSpendingKeyZatoshiToAddressMemoClosure = { _, _, _, _ in
|
synchronizerMock.sendToAddressSpendingKeyZatoshiToAddressMemoClosure = { _, _, _, _ in
|
||||||
throw "Some error"
|
throw "Some error"
|
||||||
|
@ -375,7 +379,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
|
|
||||||
let expectation = XCTestExpectation()
|
let expectation = XCTestExpectation()
|
||||||
|
|
||||||
synchronizer.sendToAddress(spendingKey: data.spendingKey, zatoshi: amount, toAddress: recipient, memo: memo)
|
synchronizer.sendToAddress(spendingKey: mockedSpendingKey, zatoshi: amount, toAddress: recipient, memo: memo)
|
||||||
.sink(
|
.sink(
|
||||||
receiveCompletion: { result in
|
receiveCompletion: { result in
|
||||||
switch result {
|
switch result {
|
||||||
|
@ -394,12 +398,13 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
wait(for: [expectation], timeout: 0.5)
|
wait(for: [expectation], timeout: 0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testShieldFundsSucceed() throws {
|
func testShieldFundsSucceed() async throws {
|
||||||
let memo: Memo = .text(try MemoText("Some message"))
|
let memo: Memo = .text(try MemoText("Some message"))
|
||||||
let shieldingThreshold = Zatoshi(1)
|
let shieldingThreshold = Zatoshi(1)
|
||||||
|
let mockedSpendingKey = await data.spendingKey
|
||||||
|
|
||||||
synchronizerMock.shieldFundsSpendingKeyMemoShieldingThresholdClosure = { receivedSpendingKey, receivedMemo, receivedShieldingThreshold in
|
synchronizerMock.shieldFundsSpendingKeyMemoShieldingThresholdClosure = { receivedSpendingKey, receivedMemo, receivedShieldingThreshold in
|
||||||
XCTAssertEqual(receivedSpendingKey, self.data.spendingKey)
|
XCTAssertEqual(receivedSpendingKey, mockedSpendingKey)
|
||||||
XCTAssertEqual(receivedMemo, memo)
|
XCTAssertEqual(receivedMemo, memo)
|
||||||
XCTAssertEqual(receivedShieldingThreshold, shieldingThreshold)
|
XCTAssertEqual(receivedShieldingThreshold, shieldingThreshold)
|
||||||
return self.data.pendingTransactionEntity
|
return self.data.pendingTransactionEntity
|
||||||
|
@ -407,7 +412,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
|
|
||||||
let expectation = XCTestExpectation()
|
let expectation = XCTestExpectation()
|
||||||
|
|
||||||
synchronizer.shieldFunds(spendingKey: data.spendingKey, memo: memo, shieldingThreshold: shieldingThreshold)
|
synchronizer.shieldFunds(spendingKey: mockedSpendingKey, memo: memo, shieldingThreshold: shieldingThreshold)
|
||||||
.sink(
|
.sink(
|
||||||
receiveCompletion: { result in
|
receiveCompletion: { result in
|
||||||
switch result {
|
switch result {
|
||||||
|
@ -426,9 +431,10 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
wait(for: [expectation], timeout: 0.5)
|
wait(for: [expectation], timeout: 0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testShieldFundsThrowsError() throws {
|
func testShieldFundsThrowsError() async throws {
|
||||||
let memo: Memo = .text(try MemoText("Some message"))
|
let memo: Memo = .text(try MemoText("Some message"))
|
||||||
let shieldingThreshold = Zatoshi(1)
|
let shieldingThreshold = Zatoshi(1)
|
||||||
|
let mockedSpendingKey = await data.spendingKey
|
||||||
|
|
||||||
synchronizerMock.shieldFundsSpendingKeyMemoShieldingThresholdClosure = { _, _, _ in
|
synchronizerMock.shieldFundsSpendingKeyMemoShieldingThresholdClosure = { _, _, _ in
|
||||||
throw "Some error"
|
throw "Some error"
|
||||||
|
@ -436,7 +442,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
|
|
||||||
let expectation = XCTestExpectation()
|
let expectation = XCTestExpectation()
|
||||||
|
|
||||||
synchronizer.shieldFunds(spendingKey: data.spendingKey, memo: memo, shieldingThreshold: shieldingThreshold)
|
synchronizer.shieldFunds(spendingKey: mockedSpendingKey, memo: memo, shieldingThreshold: shieldingThreshold)
|
||||||
.sink(
|
.sink(
|
||||||
receiveCompletion: { result in
|
receiveCompletion: { result in
|
||||||
switch result {
|
switch result {
|
||||||
|
@ -581,7 +587,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
func testGetMemosForClearedTransactionSucceed() throws {
|
func testGetMemosForClearedTransactionSucceed() throws {
|
||||||
let memo: Memo = .text(try MemoText("Some message"))
|
let memo: Memo = .text(try MemoText("Some message"))
|
||||||
|
|
||||||
synchronizerMock.getMemosForTransactionClosure = { receivedTransaction in
|
synchronizerMock.getMemosForClearedTransactionClosure = { receivedTransaction in
|
||||||
XCTAssertEqual(receivedTransaction.id, self.data.clearedTransaction.id)
|
XCTAssertEqual(receivedTransaction.id, self.data.clearedTransaction.id)
|
||||||
return [memo]
|
return [memo]
|
||||||
}
|
}
|
||||||
|
@ -608,7 +614,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGetMemosForClearedTransactionThrowsError() {
|
func testGetMemosForClearedTransactionThrowsError() {
|
||||||
synchronizerMock.getMemosForTransactionClosure = { _ in
|
synchronizerMock.getMemosForClearedTransactionClosure = { _ in
|
||||||
throw "Some error"
|
throw "Some error"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -802,7 +808,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAllConfirmedTransactionsSucceed() throws {
|
func testAllConfirmedTransactionsSucceed() throws {
|
||||||
synchronizerMock.allConfirmedTransactionsFromTransactionClosure = { receivedTransaction, limit in
|
synchronizerMock.allConfirmedTransactionsFromLimitClosure = { receivedTransaction, limit in
|
||||||
XCTAssertEqual(receivedTransaction.id, self.data.clearedTransaction.id)
|
XCTAssertEqual(receivedTransaction.id, self.data.clearedTransaction.id)
|
||||||
XCTAssertEqual(limit, 3)
|
XCTAssertEqual(limit, 3)
|
||||||
return [self.data.clearedTransaction]
|
return [self.data.clearedTransaction]
|
||||||
|
@ -830,7 +836,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAllConfirmedTransactionsThrowsError() throws {
|
func testAllConfirmedTransactionsThrowsError() throws {
|
||||||
synchronizerMock.allConfirmedTransactionsFromTransactionClosure = { _, _ in
|
synchronizerMock.allConfirmedTransactionsFromLimitClosure = { _, _ in
|
||||||
throw "Some error"
|
throw "Some error"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -910,7 +916,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
let skippedEntity = UnspentTransactionOutputEntityMock(address: "addr2", txid: Data(), index: 1, script: Data(), valueZat: 2, height: 3)
|
let skippedEntity = UnspentTransactionOutputEntityMock(address: "addr2", txid: Data(), index: 1, script: Data(), valueZat: 2, height: 3)
|
||||||
let refreshedUTXO = (inserted: [insertedEntity], skipped: [skippedEntity])
|
let refreshedUTXO = (inserted: [insertedEntity], skipped: [skippedEntity])
|
||||||
|
|
||||||
synchronizerMock.refreshUTXOsAddressFromHeightClosure = { receivedAddress, receivedFromHeight in
|
synchronizerMock.refreshUTXOsAddressFromClosure = { receivedAddress, receivedFromHeight in
|
||||||
XCTAssertEqual(receivedAddress, self.data.transparentAddress)
|
XCTAssertEqual(receivedAddress, self.data.transparentAddress)
|
||||||
XCTAssertEqual(receivedFromHeight, 121000)
|
XCTAssertEqual(receivedFromHeight, 121000)
|
||||||
return refreshedUTXO
|
return refreshedUTXO
|
||||||
|
@ -939,7 +945,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRefreshUTXOsThrowsError() {
|
func testRefreshUTXOsThrowsError() {
|
||||||
synchronizerMock.refreshUTXOsAddressFromHeightClosure = { _, _ in
|
synchronizerMock.refreshUTXOsAddressFromClosure = { _, _ in
|
||||||
throw "Some error"
|
throw "Some error"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1126,7 +1132,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRewindSucceed() {
|
func testRewindSucceed() {
|
||||||
synchronizerMock.rewindPolicyClosure = { receivedPolicy in
|
synchronizerMock.rewindClosure = { receivedPolicy in
|
||||||
if case .quick = receivedPolicy {
|
if case .quick = receivedPolicy {
|
||||||
} else {
|
} else {
|
||||||
XCTFail("Unexpected policy \(receivedPolicy)")
|
XCTFail("Unexpected policy \(receivedPolicy)")
|
||||||
|
@ -1155,7 +1161,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRewindThrowsError() {
|
func testRewindThrowsError() {
|
||||||
synchronizerMock.rewindPolicyClosure = { _ in
|
synchronizerMock.rewindClosure = { _ in
|
||||||
return Fail(error: "some error").eraseToAnyPublisher()
|
return Fail(error: "some error").eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,24 +11,22 @@ import XCTest
|
||||||
|
|
||||||
class CompactBlockProcessorOfflineTests: XCTestCase {
|
class CompactBlockProcessorOfflineTests: XCTestCase {
|
||||||
let testFileManager = FileManager()
|
let testFileManager = FileManager()
|
||||||
let testTempDirectory = URL(fileURLWithPath: NSString(
|
var testTempDirectory: URL!
|
||||||
string: NSTemporaryDirectory()
|
|
||||||
)
|
|
||||||
.appendingPathComponent("tmp-\(Int.random(in: 0 ... .max))"))
|
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
try super.setUpWithError()
|
try super.setUpWithError()
|
||||||
try self.testFileManager.createDirectory(at: self.testTempDirectory, withIntermediateDirectories: false)
|
testTempDirectory = Environment.uniqueTestTempDirectory
|
||||||
|
try self.testFileManager.createDirectory(at: testTempDirectory, withIntermediateDirectories: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
try super.tearDownWithError()
|
try super.tearDownWithError()
|
||||||
try FileManager.default.removeItem(at: self.testTempDirectory)
|
try FileManager.default.removeItem(at: testTempDirectory)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testComputeProcessingRangeForSingleLoop() async throws {
|
func testComputeProcessingRangeForSingleLoop() async throws {
|
||||||
let network = ZcashNetworkBuilder.network(for: .testnet)
|
let network = ZcashNetworkBuilder.network(for: .testnet)
|
||||||
let realRustBackend = ZcashRustBackend.self
|
let rustBackend = ZcashRustBackend.makeForTests(fsBlockDbRoot: testTempDirectory, networkType: .testnet)
|
||||||
|
|
||||||
let processorConfig = CompactBlockProcessor.Configuration.standard(
|
let processorConfig = CompactBlockProcessor.Configuration.standard(
|
||||||
for: network,
|
for: network,
|
||||||
|
@ -44,7 +42,7 @@ class CompactBlockProcessorOfflineTests: XCTestCase {
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: realRustBackend,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
@ -55,7 +53,7 @@ class CompactBlockProcessorOfflineTests: XCTestCase {
|
||||||
let processor = CompactBlockProcessor(
|
let processor = CompactBlockProcessor(
|
||||||
service: service,
|
service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
backend: ZcashRustBackend.self,
|
rustBackend: rustBackend,
|
||||||
config: processorConfig,
|
config: processorConfig,
|
||||||
metrics: SDKMetrics(),
|
metrics: SDKMetrics(),
|
||||||
logger: logger
|
logger: logger
|
||||||
|
|
|
@ -13,22 +13,22 @@ import XCTest
|
||||||
|
|
||||||
class CompactBlockRepositoryTests: XCTestCase {
|
class CompactBlockRepositoryTests: XCTestCase {
|
||||||
let network = ZcashNetworkBuilder.network(for: .testnet)
|
let network = ZcashNetworkBuilder.network(for: .testnet)
|
||||||
|
|
||||||
let testTempDirectory = URL(fileURLWithPath: NSString(
|
|
||||||
string: NSTemporaryDirectory()
|
|
||||||
)
|
|
||||||
.appendingPathComponent("tmp-\(Int.random(in: 0 ... .max))"))
|
|
||||||
|
|
||||||
let testFileManager = FileManager()
|
let testFileManager = FileManager()
|
||||||
|
var rustBackend: ZcashRustBackendWelding!
|
||||||
|
var testTempDirectory: URL!
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
try super.setUpWithError()
|
try super.setUpWithError()
|
||||||
try self.testFileManager.createDirectory(at: self.testTempDirectory, withIntermediateDirectories: false)
|
testTempDirectory = Environment.uniqueTestTempDirectory
|
||||||
|
try self.testFileManager.createDirectory(at: testTempDirectory, withIntermediateDirectories: false)
|
||||||
|
rustBackend = ZcashRustBackend.makeForTests(fsBlockDbRoot: testTempDirectory, networkType: .testnet)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
try super.tearDownWithError()
|
try super.tearDownWithError()
|
||||||
try? testFileManager.removeItem(at: testTempDirectory)
|
try? testFileManager.removeItem(at: testTempDirectory)
|
||||||
|
rustBackend = nil
|
||||||
|
testTempDirectory = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testEmptyStorage() async throws {
|
func testEmptyStorage() async throws {
|
||||||
|
@ -36,7 +36,7 @@ class CompactBlockRepositoryTests: XCTestCase {
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: ZcashRustBackend.self,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
@ -55,7 +55,7 @@ class CompactBlockRepositoryTests: XCTestCase {
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: ZcashRustBackend.self,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
@ -82,7 +82,7 @@ class CompactBlockRepositoryTests: XCTestCase {
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: ZcashRustBackend.self,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
@ -108,7 +108,7 @@ class CompactBlockRepositoryTests: XCTestCase {
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: FSMetadataStore.live(
|
metadataStore: FSMetadataStore.live(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: ZcashRustBackend.self,
|
rustBackend: rustBackend,
|
||||||
logger: logger
|
logger: logger
|
||||||
),
|
),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
|
|
|
@ -16,7 +16,8 @@ class DerivationToolMainnetTests: XCTestCase {
|
||||||
let testRecipientAddress = UnifiedAddress(
|
let testRecipientAddress = UnifiedAddress(
|
||||||
validatedEncoding: """
|
validatedEncoding: """
|
||||||
u1l9f0l4348negsncgr9pxd9d3qaxagmqv3lnexcplmufpq7muffvfaue6ksevfvd7wrz7xrvn95rc5zjtn7ugkmgh5rnxswmcj30y0pw52pn0zjvy38rn2esfgve64rj5pcmazxgpyuj
|
u1l9f0l4348negsncgr9pxd9d3qaxagmqv3lnexcplmufpq7muffvfaue6ksevfvd7wrz7xrvn95rc5zjtn7ugkmgh5rnxswmcj30y0pw52pn0zjvy38rn2esfgve64rj5pcmazxgpyuj
|
||||||
"""
|
""",
|
||||||
|
networkType: .mainnet
|
||||||
)
|
)
|
||||||
|
|
||||||
let expectedSpendingKey = UnifiedSpendingKey(
|
let expectedSpendingKey = UnifiedSpendingKey(
|
||||||
|
@ -45,82 +46,72 @@ class DerivationToolMainnetTests: XCTestCase {
|
||||||
""")
|
""")
|
||||||
|
|
||||||
let expectedSaplingAddress = SaplingAddress(validatedEncoding: "zs1vp7kvlqr4n9gpehztr76lcn6skkss9p8keqs3nv8avkdtjrcctrvmk9a7u494kluv756jeee5k0")
|
let expectedSaplingAddress = SaplingAddress(validatedEncoding: "zs1vp7kvlqr4n9gpehztr76lcn6skkss9p8keqs3nv8avkdtjrcctrvmk9a7u494kluv756jeee5k0")
|
||||||
|
|
||||||
let derivationTool = DerivationTool(networkType: NetworkType.mainnet)
|
let derivationTool = TestsData(networkType: .mainnet).derivationTools
|
||||||
let expectedTransparentAddress = TransparentAddress(validatedEncoding: "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz")
|
let expectedTransparentAddress = TransparentAddress(validatedEncoding: "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz")
|
||||||
func testDeriveViewingKeysFromSeed() throws {
|
|
||||||
|
func testDeriveViewingKeysFromSeed() async throws {
|
||||||
let seedBytes = [UInt8](seedData)
|
let seedBytes = [UInt8](seedData)
|
||||||
|
|
||||||
let spendingKey = try derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: 0)
|
let spendingKey = try await derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: 0)
|
||||||
|
let viewingKey = try await derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
let viewingKey = try derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
|
||||||
|
|
||||||
XCTAssertEqual(expectedViewingKey, viewingKey)
|
XCTAssertEqual(expectedViewingKey, viewingKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeriveViewingKeyFromSpendingKeys() throws {
|
func testDeriveViewingKeyFromSpendingKeys() async throws {
|
||||||
XCTAssertEqual(
|
let viewingKey = try await derivationTool.deriveUnifiedFullViewingKey(from: expectedSpendingKey)
|
||||||
expectedViewingKey,
|
XCTAssertEqual(expectedViewingKey, viewingKey)
|
||||||
try derivationTool.deriveUnifiedFullViewingKey(from: expectedSpendingKey)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeriveSpendingKeysFromSeed() throws {
|
func testDeriveSpendingKeysFromSeed() async throws {
|
||||||
let seedBytes = [UInt8](seedData)
|
let seedBytes = [UInt8](seedData)
|
||||||
|
|
||||||
let spendingKey = try derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: 0)
|
let spendingKey = try await derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: 0)
|
||||||
|
|
||||||
XCTAssertEqual(expectedSpendingKey, spendingKey)
|
XCTAssertEqual(expectedSpendingKey, spendingKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeriveUnifiedSpendingKeyFromSeed() throws {
|
func testDeriveUnifiedSpendingKeyFromSeed() async throws {
|
||||||
let account = 0
|
let account = 0
|
||||||
let seedBytes = [UInt8](seedData)
|
let seedBytes = [UInt8](seedData)
|
||||||
|
|
||||||
XCTAssertNoThrow(try derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: account))
|
_ = try await derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: account)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGetTransparentAddressFromUA() throws {
|
func testGetTransparentAddressFromUA() throws {
|
||||||
XCTAssertEqual(
|
XCTAssertEqual(
|
||||||
try DerivationTool.transparentReceiver(from: testRecipientAddress),
|
try DerivationTool(networkType: .mainnet).transparentReceiver(from: testRecipientAddress),
|
||||||
expectedTransparentAddress
|
expectedTransparentAddress
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testIsValidViewingKey() {
|
func testIsValidViewingKey() {
|
||||||
XCTAssertTrue(
|
XCTAssertTrue(
|
||||||
DerivationTool.rustwelding.isValidSaplingExtendedFullViewingKey(
|
ZcashKeyDerivationBackend(networkType: .mainnet).isValidSaplingExtendedFullViewingKey(
|
||||||
"""
|
"""
|
||||||
zxviews1q0dm7hkzqqqqpqplzv3f50rl4vay8uy5zg9e92f62lqg6gzu63rljety32xy5tcyenzuu3n386ws772nm6tp4sads8n37gff6nxmyz8dn9keehmapk0spc6pzx5ux\
|
zxviews1q0dm7hkzqqqqpqplzv3f50rl4vay8uy5zg9e92f62lqg6gzu63rljety32xy5tcyenzuu3n386ws772nm6tp4sads8n37gff6nxmyz8dn9keehmapk0spc6pzx5ux\
|
||||||
epgu52xnwzxxnuja5tv465t9asppnj3eqncu3s7g3gzg5x8ss4ypkw08xwwyj7ky5skvnd9ldwj2u8fz2ry94s5q8p9lyp3j96yckudmp087d2jr2rnfuvjp7f56v78vpe658\
|
epgu52xnwzxxnuja5tv465t9asppnj3eqncu3s7g3gzg5x8ss4ypkw08xwwyj7ky5skvnd9ldwj2u8fz2ry94s5q8p9lyp3j96yckudmp087d2jr2rnfuvjp7f56v78vpe658\
|
||||||
vljjddj7s645q399jd7
|
vljjddj7s645q399jd7
|
||||||
""",
|
"""
|
||||||
networkType: .mainnet
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
XCTAssertFalse(
|
XCTAssertFalse(
|
||||||
DerivationTool.rustwelding.isValidSaplingExtendedFullViewingKey(
|
ZcashKeyDerivationBackend(networkType: .mainnet).isValidSaplingExtendedFullViewingKey(
|
||||||
"zxviews1q0dm7hkzky5skvnd9ldwj2u8fz2ry94s5q8p9lyp3j96yckudmp087d2jr2rnfuvjp7f56v78vpe658vljjddj7s645q399jd7",
|
"zxviews1q0dm7hkzky5skvnd9ldwj2u8fz2ry94s5q8p9lyp3j96yckudmp087d2jr2rnfuvjp7f56v78vpe658vljjddj7s645q399jd7"
|
||||||
networkType: .mainnet
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeriveQuiteALotOfUnifiedKeysFromSeed() throws {
|
func testDeriveQuiteALotOfUnifiedKeysFromSeed() async throws {
|
||||||
let numberOfAccounts: Int = 10
|
let numberOfAccounts: Int = 10
|
||||||
let ufvks = try (0 ..< numberOfAccounts)
|
var ufvks: [UnifiedFullViewingKey] = []
|
||||||
.map({
|
for i in 0..<numberOfAccounts {
|
||||||
try derivationTool.deriveUnifiedSpendingKey(
|
let spendingKey = try await derivationTool.deriveUnifiedSpendingKey(seed: [UInt8](seedData), accountIndex: i)
|
||||||
seed: [UInt8](seedData),
|
let viewingKey = try await derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
accountIndex: $0
|
ufvks.append(viewingKey)
|
||||||
)
|
}
|
||||||
})
|
|
||||||
.map {
|
|
||||||
try derivationTool.deriveUnifiedFullViewingKey(
|
|
||||||
from: $0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
XCTAssertEqual(ufvks.count, numberOfAccounts)
|
XCTAssertEqual(ufvks.count, numberOfAccounts)
|
||||||
XCTAssertEqual(ufvks[0].account, 0)
|
XCTAssertEqual(ufvks[0].account, 0)
|
||||||
|
@ -129,7 +120,7 @@ class DerivationToolMainnetTests: XCTestCase {
|
||||||
|
|
||||||
func testShouldFailOnInvalidChecksumAddresses() {
|
func testShouldFailOnInvalidChecksumAddresses() {
|
||||||
let testAddress = "t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1"
|
let testAddress = "t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1"
|
||||||
XCTAssertFalse(derivationTool.isValidTransparentAddress(testAddress))
|
XCTAssertFalse(DerivationTool(networkType: .mainnet).isValidTransparentAddress(testAddress))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSpendingKeyValidationFailsOnInvalidKey() throws {
|
func testSpendingKeyValidationFailsOnInvalidKey() throws {
|
||||||
|
@ -139,7 +130,7 @@ class DerivationToolMainnetTests: XCTestCase {
|
||||||
4fsuaz686lgszc7nc9vvZzZzZz
|
4fsuaz686lgszc7nc9vvZzZzZz
|
||||||
"""
|
"""
|
||||||
|
|
||||||
XCTAssertFalse(derivationTool.isValidSaplingExtendedSpendingKey(wrongSpendingKey))
|
XCTAssertFalse(DerivationTool(networkType: .mainnet).isValidSaplingExtendedSpendingKey(wrongSpendingKey))
|
||||||
}
|
}
|
||||||
// TODO: [#509] Address encoding does not catch this test https://github.com/zcash/ZcashLightClientKit/issues/509
|
// TODO: [#509] Address encoding does not catch this test https://github.com/zcash/ZcashLightClientKit/issues/509
|
||||||
// func testSpendingKeyValidationThrowsWhenWrongNetwork() throws {
|
// func testSpendingKeyValidationThrowsWhenWrongNetwork() throws {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
// swift-format-ignore-file
|
// swift-format-ignore-file
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
|
@testable import TestUtils
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
class DerivationToolTestnetTests: XCTestCase {
|
class DerivationToolTestnetTests: XCTestCase {
|
||||||
|
@ -16,7 +17,8 @@ class DerivationToolTestnetTests: XCTestCase {
|
||||||
validatedEncoding: """
|
validatedEncoding: """
|
||||||
utest1uqmec4a2njqz2z2rwppchsd06qe7a0jh4jmsqr0yy99m9er9646zlxunf3v8qr0hncgv86e8a62vxy0qa32qzetmj8s57yudmyx9zav6f52nurclsqjkqtjtpz6vg679p6wkcz\
|
utest1uqmec4a2njqz2z2rwppchsd06qe7a0jh4jmsqr0yy99m9er9646zlxunf3v8qr0hncgv86e8a62vxy0qa32qzetmj8s57yudmyx9zav6f52nurclsqjkqtjtpz6vg679p6wkcz\
|
||||||
pl2wu
|
pl2wu
|
||||||
"""
|
""",
|
||||||
|
networkType: .testnet
|
||||||
)
|
)
|
||||||
|
|
||||||
let expectedSpendingKey = UnifiedSpendingKey(
|
let expectedSpendingKey = UnifiedSpendingKey(
|
||||||
|
@ -53,15 +55,14 @@ class DerivationToolTestnetTests: XCTestCase {
|
||||||
validatedEncoding: "ztestsapling1475xtm56czrzmleqzzlu4cxvjjfsy2p6rv78q07232cpsx5ee52k0mn5jyndq09mampkgvrxnwg"
|
validatedEncoding: "ztestsapling1475xtm56czrzmleqzzlu4cxvjjfsy2p6rv78q07232cpsx5ee52k0mn5jyndq09mampkgvrxnwg"
|
||||||
)
|
)
|
||||||
|
|
||||||
let derivationTool = DerivationTool(networkType: NetworkType.testnet)
|
let derivationTool = TestsData(networkType: .testnet).derivationTools
|
||||||
let expectedTransparentAddress = TransparentAddress(validatedEncoding: "tmXuTnE11JojToagTqxXUn6KvdxDE3iLKbp")
|
let expectedTransparentAddress = TransparentAddress(validatedEncoding: "tmXuTnE11JojToagTqxXUn6KvdxDE3iLKbp")
|
||||||
|
|
||||||
func testDeriveViewingKeysFromSeed() throws {
|
func testDeriveViewingKeysFromSeed() async throws {
|
||||||
let seedBytes = [UInt8](seedData)
|
let seedBytes = [UInt8](seedData)
|
||||||
|
|
||||||
let spendingKey = try derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: 0)
|
let spendingKey = try await derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: 0)
|
||||||
|
let viewingKey = try await derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
let viewingKey = try derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
|
||||||
|
|
||||||
XCTAssertEqual(expectedViewingKey, viewingKey)
|
XCTAssertEqual(expectedViewingKey, viewingKey)
|
||||||
}
|
}
|
||||||
|
@ -73,62 +74,54 @@ class DerivationToolTestnetTests: XCTestCase {
|
||||||
// )
|
// )
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeriveSpendingKeysFromSeed() throws {
|
func testDeriveSpendingKeysFromSeed() async throws {
|
||||||
let seedBytes = [UInt8](seedData)
|
let seedBytes = [UInt8](seedData)
|
||||||
|
|
||||||
let spendingKey = try derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: 0)
|
let spendingKey = try await derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: 0)
|
||||||
|
|
||||||
XCTAssertEqual(expectedSpendingKey, spendingKey)
|
XCTAssertEqual(expectedSpendingKey, spendingKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeriveUnifiedSpendingKeyFromSeed() throws {
|
func testDeriveUnifiedSpendingKeyFromSeed() async throws {
|
||||||
let account = 0
|
let account = 0
|
||||||
let seedBytes = [UInt8](seedData)
|
let seedBytes = [UInt8](seedData)
|
||||||
|
|
||||||
XCTAssertNoThrow(try derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: account))
|
_ = try await derivationTool.deriveUnifiedSpendingKey(seed: seedBytes, accountIndex: account)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGetTransparentAddressFromUA() throws {
|
func testGetTransparentAddressFromUA() throws {
|
||||||
XCTAssertEqual(
|
XCTAssertEqual(
|
||||||
try DerivationTool.transparentReceiver(from: testRecipientAddress),
|
try DerivationTool(networkType: .testnet).transparentReceiver(from: testRecipientAddress),
|
||||||
expectedTransparentAddress
|
expectedTransparentAddress
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testIsValidViewingKey() throws {
|
func testIsValidViewingKey() throws {
|
||||||
XCTAssertTrue(
|
XCTAssertTrue(
|
||||||
DerivationTool.rustwelding.isValidSaplingExtendedFullViewingKey(
|
ZcashKeyDerivationBackend(networkType: .testnet).isValidSaplingExtendedFullViewingKey(
|
||||||
"""
|
"""
|
||||||
zxviewtestsapling1qdxykmuaqqqqpqqg3x5c02p4rhw0rtszr8ln4xl7g6wg6qzsqgn445qsu3cq4vd6l5smlqrckkl2x5rnrauzc4gp665q3zyw0qf2sfdsx5wpp832htf\
|
zxviewtestsapling1qdxykmuaqqqqpqqg3x5c02p4rhw0rtszr8ln4xl7g6wg6qzsqgn445qsu3cq4vd6l5smlqrckkl2x5rnrauzc4gp665q3zyw0qf2sfdsx5wpp832htf\
|
||||||
avqk72uchuuvq2dpmgk8jfaza5t5l56u66fpx0sr8ewp9s3wj2txavmhhlazn5rj8mshh470fkrmzg4xarhrqlygg8f486307ujhndwhsw2h7ddzf89k3534aeu0ypz2tjgrz\
|
avqk72uchuuvq2dpmgk8jfaza5t5l56u66fpx0sr8ewp9s3wj2txavmhhlazn5rj8mshh470fkrmzg4xarhrqlygg8f486307ujhndwhsw2h7ddzf89k3534aeu0ypz2tjgrz\
|
||||||
lcqtat380vhe8awm03f58cqgegsaj
|
lcqtat380vhe8awm03f58cqgegsaj
|
||||||
""",
|
"""
|
||||||
networkType: .testnet
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
XCTAssertFalse(
|
XCTAssertFalse(
|
||||||
DerivationTool.rustwelding.isValidSaplingExtendedFullViewingKey(
|
ZcashKeyDerivationBackend(networkType: .testnet).isValidSaplingExtendedFullViewingKey(
|
||||||
"zxviews1q0dm7hkzky5skvnd9ldwj2u8fz2ry94s5q8p9lyp3j96yckudmp087d2jr2rnfuvjp7f56v78vpe658vljjddj7s645q399jd7",
|
"zxviews1q0dm7hkzky5skvnd9ldwj2u8fz2ry94s5q8p9lyp3j96yckudmp087d2jr2rnfuvjp7f56v78vpe658vljjddj7s645q399jd7"
|
||||||
networkType: .testnet
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeriveQuiteALotOfUnifiedKeysFromSeed() throws {
|
func testDeriveQuiteALotOfUnifiedKeysFromSeed() async throws {
|
||||||
let numberOfAccounts: Int = 10
|
let numberOfAccounts: Int = 10
|
||||||
let ufvks = try (0 ..< numberOfAccounts)
|
var ufvks: [UnifiedFullViewingKey] = []
|
||||||
.map({
|
for i in 0..<numberOfAccounts {
|
||||||
try derivationTool.deriveUnifiedSpendingKey(
|
let spendingKey = try await derivationTool.deriveUnifiedSpendingKey(seed: [UInt8](seedData), accountIndex: i)
|
||||||
seed: [UInt8](seedData),
|
let viewingKey = try await derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
accountIndex: $0
|
ufvks.append(viewingKey)
|
||||||
)
|
}
|
||||||
})
|
|
||||||
.map {
|
|
||||||
try derivationTool.deriveUnifiedFullViewingKey(
|
|
||||||
from: $0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
XCTAssertEqual(ufvks.count, numberOfAccounts)
|
XCTAssertEqual(ufvks.count, numberOfAccounts)
|
||||||
XCTAssertEqual(ufvks[0].account, 0)
|
XCTAssertEqual(ufvks[0].account, 0)
|
||||||
|
@ -137,7 +130,7 @@ class DerivationToolTestnetTests: XCTestCase {
|
||||||
|
|
||||||
func testShouldFailOnInvalidChecksumAddresses() throws {
|
func testShouldFailOnInvalidChecksumAddresses() throws {
|
||||||
let testAddress = "t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1"
|
let testAddress = "t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1"
|
||||||
XCTAssertFalse(derivationTool.isValidTransparentAddress(testAddress))
|
XCTAssertFalse(DerivationTool(networkType: .testnet).isValidTransparentAddress(testAddress))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSpendingKeyValidationFailsOnInvalidKey() {
|
func testSpendingKeyValidationFailsOnInvalidKey() {
|
||||||
|
@ -147,7 +140,7 @@ class DerivationToolTestnetTests: XCTestCase {
|
||||||
4fsuaz686lgszc7nc9vvZzZzZz
|
4fsuaz686lgszc7nc9vvZzZzZz
|
||||||
"""
|
"""
|
||||||
|
|
||||||
XCTAssertFalse(derivationTool.isValidSaplingExtendedSpendingKey(wrongSpendingKey))
|
XCTAssertFalse(DerivationTool(networkType: .testnet).isValidSaplingExtendedSpendingKey(wrongSpendingKey))
|
||||||
}
|
}
|
||||||
// TODO: [#509] Address encoding does not catch this test https://github.com/zcash/ZcashLightClientKit/issues/509
|
// TODO: [#509] Address encoding does not catch this test https://github.com/zcash/ZcashLightClientKit/issues/509
|
||||||
// func testSpendingKeyValidationThrowsWhenWrongNetwork() throws {
|
// func testSpendingKeyValidationThrowsWhenWrongNetwork() throws {
|
||||||
|
|
|
@ -11,26 +11,27 @@ import XCTest
|
||||||
var logger = OSLogger(logLevel: .debug)
|
var logger = OSLogger(logLevel: .debug)
|
||||||
|
|
||||||
final class FsBlockStorageTests: XCTestCase {
|
final class FsBlockStorageTests: XCTestCase {
|
||||||
let testTempDirectory = URL(fileURLWithPath: NSString(
|
|
||||||
string: NSTemporaryDirectory()
|
|
||||||
)
|
|
||||||
.appendingPathComponent("tmp-\(Int.random(in: 0 ... .max))"))
|
|
||||||
|
|
||||||
let testFileManager = FileManager()
|
let testFileManager = FileManager()
|
||||||
|
|
||||||
var fsBlockDb: URL!
|
var fsBlockDb: URL!
|
||||||
|
var rustBackend: ZcashRustBackendWelding!
|
||||||
|
var testTempDirectory: URL!
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
try super.setUpWithError()
|
try super.setUpWithError()
|
||||||
|
testTempDirectory = Environment.uniqueTestTempDirectory
|
||||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
self.fsBlockDb = self.testTempDirectory.appendingPathComponent("FsBlockDb-\(Int.random(in: 0 ... .max))")
|
self.fsBlockDb = testTempDirectory.appendingPathComponent("FsBlockDb-\(Int.random(in: 0 ... .max))")
|
||||||
try self.testFileManager.createDirectory(at: self.testTempDirectory, withIntermediateDirectories: false)
|
try self.testFileManager.createDirectory(at: testTempDirectory, withIntermediateDirectories: false)
|
||||||
try self.testFileManager.createDirectory(at: self.fsBlockDb, withIntermediateDirectories: false)
|
try self.testFileManager.createDirectory(at: self.fsBlockDb, withIntermediateDirectories: false)
|
||||||
|
|
||||||
|
rustBackend = ZcashRustBackend.makeForTests(fsBlockDbRoot: testTempDirectory, networkType: .testnet)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
try super.tearDownWithError()
|
try super.tearDownWithError()
|
||||||
try? testFileManager.removeItem(at: testTempDirectory)
|
try? testFileManager.removeItem(at: testTempDirectory)
|
||||||
|
rustBackend = nil
|
||||||
|
testTempDirectory = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testLatestHeightEmptyCache() async throws {
|
func testLatestHeightEmptyCache() async throws {
|
||||||
|
@ -54,7 +55,7 @@ final class FsBlockStorageTests: XCTestCase {
|
||||||
let blockNameFixture = "This-is-a-fixture"
|
let blockNameFixture = "This-is-a-fixture"
|
||||||
|
|
||||||
let freshCache = FSCompactBlockRepository(
|
let freshCache = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: self.testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: .mock,
|
metadataStore: .mock,
|
||||||
blockDescriptor: ZcashCompactBlockDescriptor(
|
blockDescriptor: ZcashCompactBlockDescriptor(
|
||||||
height: { _ in nil },
|
height: { _ in nil },
|
||||||
|
@ -170,7 +171,7 @@ final class FsBlockStorageTests: XCTestCase {
|
||||||
func testGetLatestHeight() async throws {
|
func testGetLatestHeight() async throws {
|
||||||
let freshCache = FSCompactBlockRepository(
|
let freshCache = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: ZcashRustBackend.self, logger: logger),
|
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: rustBackend, logger: logger),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
contentProvider: DirectoryListingProviders.defaultSorted,
|
contentProvider: DirectoryListingProviders.defaultSorted,
|
||||||
logger: logger
|
logger: logger
|
||||||
|
@ -281,8 +282,8 @@ final class FsBlockStorageTests: XCTestCase {
|
||||||
|
|
||||||
func testClearTheCache() async throws {
|
func testClearTheCache() async throws {
|
||||||
let fsBlockCache = FSCompactBlockRepository(
|
let fsBlockCache = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: self.testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: ZcashRustBackend.self, logger: logger),
|
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: rustBackend, logger: logger),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
contentProvider: DirectoryListingProviders.naive,
|
contentProvider: DirectoryListingProviders.naive,
|
||||||
logger: logger
|
logger: logger
|
||||||
|
@ -319,11 +320,9 @@ final class FsBlockStorageTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func disabled_testStoringTenSandblastedBlocks() async throws {
|
func disabled_testStoringTenSandblastedBlocks() async throws {
|
||||||
let realRustBackend = ZcashRustBackend.self
|
|
||||||
|
|
||||||
let realCache = FSCompactBlockRepository(
|
let realCache = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: realRustBackend, logger: logger),
|
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: rustBackend, logger: logger),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
contentProvider: DirectoryListingProviders.defaultSorted,
|
contentProvider: DirectoryListingProviders.defaultSorted,
|
||||||
logger: logger
|
logger: logger
|
||||||
|
@ -350,11 +349,9 @@ final class FsBlockStorageTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStoringTenSandblastedBlocksFailsAndThrows() async throws {
|
func testStoringTenSandblastedBlocksFailsAndThrows() async throws {
|
||||||
let realRustBackend = ZcashRustBackend.self
|
|
||||||
|
|
||||||
let realCache = FSCompactBlockRepository(
|
let realCache = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: realRustBackend, logger: logger),
|
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: rustBackend, logger: logger),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
contentProvider: DirectoryListingProviders.defaultSorted,
|
contentProvider: DirectoryListingProviders.defaultSorted,
|
||||||
fileWriter: FSBlockFileWriter(writeToURL: { _, _ in throw FixtureError.arbitraryError }),
|
fileWriter: FSBlockFileWriter(writeToURL: { _, _ in throw FixtureError.arbitraryError }),
|
||||||
|
@ -377,11 +374,9 @@ final class FsBlockStorageTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStoringTenSandblastedBlocksAndRewindFiveThenStoreThemBack() async throws {
|
func testStoringTenSandblastedBlocksAndRewindFiveThenStoreThemBack() async throws {
|
||||||
let realRustBackend = ZcashRustBackend.self
|
|
||||||
|
|
||||||
let realCache = FSCompactBlockRepository(
|
let realCache = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: realRustBackend, logger: logger),
|
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: rustBackend, logger: logger),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
contentProvider: DirectoryListingProviders.defaultSorted,
|
contentProvider: DirectoryListingProviders.defaultSorted,
|
||||||
logger: logger
|
logger: logger
|
||||||
|
@ -420,41 +415,19 @@ final class FsBlockStorageTests: XCTestCase {
|
||||||
XCTAssertEqual(newLatestHeight, 19)
|
XCTAssertEqual(newLatestHeight, 19)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testMetadataStoreThrowsWhenCallReturnsFalse() async {
|
|
||||||
guard let sandblastedBlocks = try? SandblastSimulator().sandblast(with: CompactBlockRange(uncheckedBounds: (10, 19))) else {
|
|
||||||
XCTFail("failed to create sandblasted blocks")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
MockRustBackend.writeBlocksMetadataResult = { false }
|
|
||||||
|
|
||||||
do {
|
|
||||||
try await FSMetadataStore.saveBlocksMeta(
|
|
||||||
sandblastedBlocks,
|
|
||||||
fsBlockDbRoot: testTempDirectory,
|
|
||||||
rustBackend: MockRustBackend.self,
|
|
||||||
logger: logger
|
|
||||||
)
|
|
||||||
} catch CompactBlockRepositoryError.failedToWriteMetadata {
|
|
||||||
// this is fine
|
|
||||||
} catch {
|
|
||||||
XCTFail("Expected `CompactBlockRepositoryError.failedToWriteMetadata` but found: \(error.localizedDescription)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testMetadataStoreThrowsWhenRustThrows() async {
|
func testMetadataStoreThrowsWhenRustThrows() async {
|
||||||
guard let sandblastedBlocks = try? SandblastSimulator().sandblast(with: CompactBlockRange(uncheckedBounds: (10, 19))) else {
|
guard let sandblastedBlocks = try? SandblastSimulator().sandblast(with: CompactBlockRange(uncheckedBounds: (10, 19))) else {
|
||||||
XCTFail("failed to create sandblasted blocks")
|
XCTFail("failed to create sandblasted blocks")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
let mockBackend = await RustBackendMockHelper(rustBackend: rustBackend)
|
||||||
MockRustBackend.writeBlocksMetadataResult = { throw RustWeldingError.genericError(message: "oops") }
|
await mockBackend.rustBackendMock.setWriteBlocksMetadataBlocksThrowableError(RustWeldingError.genericError(message: "oops"))
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try await FSMetadataStore.saveBlocksMeta(
|
try await FSMetadataStore.saveBlocksMeta(
|
||||||
sandblastedBlocks,
|
sandblastedBlocks,
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: MockRustBackend.self,
|
rustBackend: mockBackend.rustBackendMock,
|
||||||
logger: logger
|
logger: logger
|
||||||
)
|
)
|
||||||
} catch CompactBlockRepositoryError.failedToWriteMetadata {
|
} catch CompactBlockRepositoryError.failedToWriteMetadata {
|
||||||
|
@ -465,13 +438,15 @@ final class FsBlockStorageTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testMetadataStoreThrowsWhenRewindFails() async {
|
func testMetadataStoreThrowsWhenRewindFails() async {
|
||||||
MockRustBackend.rewindCacheToHeightResult = { false }
|
let mockBackend = await RustBackendMockHelper(rustBackend: rustBackend)
|
||||||
|
await mockBackend.rustBackendMock.setRewindCacheToHeightHeightThrowableError(RustWeldingError.genericError(message: "oops"))
|
||||||
|
|
||||||
let expectedHeight = BlockHeight(1000)
|
let expectedHeight = BlockHeight(1000)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try await FSMetadataStore.live(
|
try await FSMetadataStore.live(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
rustBackend: MockRustBackend.self,
|
rustBackend: mockBackend.rustBackendMock,
|
||||||
logger: logger
|
logger: logger
|
||||||
)
|
)
|
||||||
.rewindToHeight(expectedHeight)
|
.rewindToHeight(expectedHeight)
|
||||||
|
@ -496,7 +471,7 @@ final class FsBlockStorageTests: XCTestCase {
|
||||||
// NOTE: performance tests don't work with async code. Thanks Apple!
|
// NOTE: performance tests don't work with async code. Thanks Apple!
|
||||||
let freshCache = FSCompactBlockRepository(
|
let freshCache = FSCompactBlockRepository(
|
||||||
fsBlockDbRoot: testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: ZcashRustBackend.self, logger: logger),
|
metadataStore: .live(fsBlockDbRoot: testTempDirectory, rustBackend: rustBackend, logger: logger),
|
||||||
blockDescriptor: .live,
|
blockDescriptor: .live,
|
||||||
contentProvider: DirectoryListingProviders.defaultSorted,
|
contentProvider: DirectoryListingProviders.defaultSorted,
|
||||||
logger: logger
|
logger: logger
|
||||||
|
@ -551,7 +526,7 @@ extension FSMetadataStore {
|
||||||
static let mock = FSMetadataStore(
|
static let mock = FSMetadataStore(
|
||||||
saveBlocksMeta: { _ in },
|
saveBlocksMeta: { _ in },
|
||||||
rewindToHeight: { _ in },
|
rewindToHeight: { _ in },
|
||||||
initFsBlockDbRoot: { _ in true },
|
initFsBlockDbRoot: { },
|
||||||
latestHeight: { .empty() }
|
latestHeight: { .empty() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,9 @@ class NotesRepositoryTests: XCTestCase {
|
||||||
|
|
||||||
override func setUp() async throws {
|
override func setUp() async throws {
|
||||||
try await super.setUp()
|
try await super.setUp()
|
||||||
sentNotesRepository = try! await TestDbBuilder.sentNotesRepository()
|
let rustBackend = ZcashRustBackend.makeForTests(fsBlockDbRoot: Environment.uniqueTestTempDirectory, networkType: .testnet)
|
||||||
receivedNotesRepository = try! await TestDbBuilder.receivedNotesRepository()
|
sentNotesRepository = try! await TestDbBuilder.sentNotesRepository(rustBackend: rustBackend)
|
||||||
|
receivedNotesRepository = try! await TestDbBuilder.receivedNotesRepository(rustBackend: rustBackend)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
override func tearDown() {
|
||||||
|
|
|
@ -17,15 +17,15 @@ class NullBytesTests: XCTestCase {
|
||||||
let validZaddr = "zs1gqtfu59z20s9t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp"
|
let validZaddr = "zs1gqtfu59z20s9t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp"
|
||||||
let zAddrWithNullBytes = "\(validZaddr)\0something else that makes the address invalid"
|
let zAddrWithNullBytes = "\(validZaddr)\0something else that makes the address invalid"
|
||||||
|
|
||||||
XCTAssertFalse(ZcashRustBackend.isValidSaplingAddress(zAddrWithNullBytes, networkType: networkType))
|
XCTAssertFalse(DerivationTool(networkType: networkType).isValidSaplingAddress(zAddrWithNullBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testTaddrNullBytes() throws {
|
func testTaddrNullBytes() throws {
|
||||||
// this is a valid tAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/
|
// this is a valid tAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/
|
||||||
let validTAddr = "t1J5pTRzJi7j8Xw9VJTrPxPEkaigr69gKVT"
|
let validTAddr = "t1J5pTRzJi7j8Xw9VJTrPxPEkaigr69gKVT"
|
||||||
let tAddrWithNullBytes = "\(validTAddr)\0fasdfasdf"
|
let tAddrWithNullBytes = "\(validTAddr)\0fasdfasdf"
|
||||||
|
|
||||||
XCTAssertFalse(ZcashRustBackend.isValidTransparentAddress(tAddrWithNullBytes, networkType: networkType))
|
XCTAssertFalse(DerivationTool(networkType: networkType).isValidTransparentAddress(tAddrWithNullBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testInitAccountTableNullBytes() async throws {
|
func testInitAccountTableNullBytes() async throws {
|
||||||
|
@ -50,14 +50,18 @@ class NullBytesTests: XCTestCase {
|
||||||
934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260
|
934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
let rustBackend = ZcashRustBackend.makeForTests(
|
||||||
|
dbData: try! __dataDbURL(),
|
||||||
|
fsBlockDbRoot: Environment.uniqueTestTempDirectory,
|
||||||
|
networkType: networkType
|
||||||
|
)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
_ = try await ZcashRustBackend.initBlocksTable(
|
_ = try await rustBackend.initBlocksTable(
|
||||||
dbData: __dataDbURL(),
|
|
||||||
height: height,
|
height: height,
|
||||||
hash: wrongHash,
|
hash: wrongHash,
|
||||||
time: time,
|
time: time,
|
||||||
saplingTree: goodTree,
|
saplingTree: goodTree
|
||||||
networkType: networkType
|
|
||||||
)
|
)
|
||||||
XCTFail("InitBlocksTable with Null bytes on hash string should have failed")
|
XCTFail("InitBlocksTable with Null bytes on hash string should have failed")
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -75,13 +79,11 @@ class NullBytesTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try await ZcashRustBackend.initBlocksTable(
|
try await rustBackend.initBlocksTable(
|
||||||
dbData: __dataDbURL(),
|
|
||||||
height: height,
|
height: height,
|
||||||
hash: goodHash,
|
hash: goodHash,
|
||||||
time: time,
|
time: time,
|
||||||
saplingTree: wrongTree,
|
saplingTree: wrongTree
|
||||||
networkType: networkType
|
|
||||||
)
|
)
|
||||||
XCTFail("InitBlocksTable with Null bytes on saplingTree string should have failed")
|
XCTFail("InitBlocksTable with Null bytes on saplingTree string should have failed")
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -106,7 +108,7 @@ class NullBytesTests: XCTestCase {
|
||||||
// let goodSpendingKeys = SaplingExtendedSpendingKey(validatedEncoding: "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mquy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv")
|
// let goodSpendingKeys = SaplingExtendedSpendingKey(validatedEncoding: "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mquy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv")
|
||||||
//
|
//
|
||||||
// XCTAssertThrowsError(
|
// XCTAssertThrowsError(
|
||||||
// try ZcashRustBackend.deriveSaplingExtendedFullViewingKey(wrongSpendingKeys, networkType: networkType),
|
// try DerivationTool(networkType: networkType)deriveSaplingExtendedFullViewingKey(wrongSpendingKeys, networkType: networkType),
|
||||||
// "Should have thrown an error but didn't! this is dangerous!"
|
// "Should have thrown an error but didn't! this is dangerous!"
|
||||||
// ) { error in
|
// ) { error in
|
||||||
// guard let rustError = error as? RustWeldingError else {
|
// guard let rustError = error as? RustWeldingError else {
|
||||||
|
@ -122,7 +124,7 @@ class NullBytesTests: XCTestCase {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// XCTAssertNoThrow(try ZcashRustBackend.deriveSaplingExtendedFullViewingKey(goodSpendingKeys, networkType: networkType))
|
// XCTAssertNoThrow(try DerivationTool(networkType: networkType)deriveSaplingExtendedFullViewingKey(goodSpendingKeys, networkType: networkType))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCheckNullBytes() throws {
|
func testCheckNullBytes() throws {
|
||||||
|
|
|
@ -17,7 +17,7 @@ final class RecipientTests: XCTestCase {
|
||||||
let transparentString = "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz"
|
let transparentString = "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz"
|
||||||
|
|
||||||
func testUnifiedRecipient() throws {
|
func testUnifiedRecipient() throws {
|
||||||
let expectedUnifiedAddress = UnifiedAddress(validatedEncoding: uaString)
|
let expectedUnifiedAddress = UnifiedAddress(validatedEncoding: uaString, networkType: .mainnet)
|
||||||
|
|
||||||
XCTAssertEqual(try Recipient(uaString, network: .mainnet), .unified(expectedUnifiedAddress))
|
XCTAssertEqual(try Recipient(uaString, network: .mainnet), .unified(expectedUnifiedAddress))
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
class SynchronizerOfflineTests: XCTestCase {
|
class SynchronizerOfflineTests: XCTestCase {
|
||||||
let data = AlternativeSynchronizerAPITestsData()
|
let data = TestsData(networkType: .testnet)
|
||||||
var network: ZcashNetwork!
|
var network: ZcashNetwork!
|
||||||
var cancellables: [AnyCancellable] = []
|
var cancellables: [AnyCancellable] = []
|
||||||
|
|
||||||
|
@ -257,12 +257,12 @@ class SynchronizerOfflineTests: XCTestCase {
|
||||||
let synchronizer = SDKSynchronizer(initializer: initializer)
|
let synchronizer = SDKSynchronizer(initializer: initializer)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let derivationTool = DerivationTool(networkType: network.networkType)
|
let derivationTool = initializer.makeDerivationTool()
|
||||||
let spendingKey = try derivationTool.deriveUnifiedSpendingKey(
|
let spendingKey = try await derivationTool.deriveUnifiedSpendingKey(
|
||||||
seed: Environment.seedBytes,
|
seed: Environment.seedBytes,
|
||||||
accountIndex: 0
|
accountIndex: 0
|
||||||
)
|
)
|
||||||
let viewingKey = try derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
let viewingKey = try await derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
_ = try await synchronizer.prepare(with: Environment.seedBytes, viewingKeys: [viewingKey], walletBirthday: 123000)
|
_ = try await synchronizer.prepare(with: Environment.seedBytes, viewingKeys: [viewingKey], walletBirthday: 123000)
|
||||||
XCTFail("Failure of prepare is expected.")
|
XCTFail("Failure of prepare is expected.")
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -350,7 +350,6 @@ class SynchronizerOfflineTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testIsNewSyncSessionWhenRestartingFromError() {
|
func testIsNewSyncSessionWhenRestartingFromError() {
|
||||||
|
|
||||||
XCTAssertTrue(
|
XCTAssertTrue(
|
||||||
SessionTicker.live.isNewSyncSession(
|
SessionTicker.live.isNewSyncSession(
|
||||||
.error(SynchronizerError.generalError(message: "some error")),
|
.error(SynchronizerError.generalError(message: "some error")),
|
||||||
|
|
|
@ -14,7 +14,8 @@ class TransactionRepositoryTests: XCTestCase {
|
||||||
|
|
||||||
override func setUp() async throws {
|
override func setUp() async throws {
|
||||||
try await super.setUp()
|
try await super.setUp()
|
||||||
transactionRepository = try! await TestDbBuilder.transactionRepository()
|
let rustBackend = ZcashRustBackend.makeForTests(fsBlockDbRoot: Environment.uniqueTestTempDirectory, networkType: .testnet)
|
||||||
|
transactionRepository = try! await TestDbBuilder.transactionRepository(rustBackend: rustBackend)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
override func tearDown() {
|
||||||
|
|
|
@ -28,11 +28,11 @@ final class UnifiedTypecodesTests: XCTestCase {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let address = UnifiedAddress(validatedEncoding: uAddress)
|
let address = UnifiedAddress(validatedEncoding: uAddress, networkType: .testnet)
|
||||||
|
|
||||||
let typecodes = try ZcashRustBackend.receiverTypecodesOnUnifiedAddress(address.stringEncoded)
|
let typecodes = try DerivationTool(networkType: .testnet).receiverTypecodesFromUnifiedAddress(address)
|
||||||
|
|
||||||
XCTAssertEqual(typecodes, [2, 0])
|
XCTAssertEqual(typecodes, [.sapling, .p2pkh])
|
||||||
}
|
}
|
||||||
|
|
||||||
func testUnifiedAddressHasTransparentSaplingReceivers() throws {
|
func testUnifiedAddressHasTransparentSaplingReceivers() throws {
|
||||||
|
@ -44,9 +44,9 @@ final class UnifiedTypecodesTests: XCTestCase {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let address = UnifiedAddress(validatedEncoding: uAddress)
|
let address = UnifiedAddress(validatedEncoding: uAddress, networkType: .testnet)
|
||||||
|
|
||||||
let typecodes = try DerivationTool.receiverTypecodesFromUnifiedAddress(address)
|
let typecodes = try DerivationTool(networkType: .testnet).receiverTypecodesFromUnifiedAddress(address)
|
||||||
|
|
||||||
XCTAssertEqual(
|
XCTAssertEqual(
|
||||||
Set<UnifiedAddress.ReceiverTypecodes>(typecodes),
|
Set<UnifiedAddress.ReceiverTypecodes>(typecodes),
|
||||||
|
@ -70,7 +70,8 @@ final class UnifiedTypecodesTests: XCTestCase {
|
||||||
validatedEncoding: """
|
validatedEncoding: """
|
||||||
u1l9f0l4348negsncgr9pxd9d3qaxagmqv3lnexcplmufpq7muffvfaue6ksevfvd7wrz7xrvn95rc5zjtn7ugkmgh5rnxswmcj30y0pw52pn0zjvy38rn2esfgve64rj5pcmazxg\
|
u1l9f0l4348negsncgr9pxd9d3qaxagmqv3lnexcplmufpq7muffvfaue6ksevfvd7wrz7xrvn95rc5zjtn7ugkmgh5rnxswmcj30y0pw52pn0zjvy38rn2esfgve64rj5pcmazxg\
|
||||||
pyuj
|
pyuj
|
||||||
"""
|
""",
|
||||||
|
networkType: .testnet
|
||||||
)
|
)
|
||||||
|
|
||||||
XCTAssertEqual(try ua.availableReceiverTypecodes(), [.sapling, .p2pkh])
|
XCTAssertEqual(try ua.availableReceiverTypecodes(), [.sapling, .p2pkh])
|
||||||
|
|
|
@ -12,13 +12,8 @@ import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
class WalletTests: XCTestCase {
|
class WalletTests: XCTestCase {
|
||||||
let testTempDirectory = URL(fileURLWithPath: NSString(
|
|
||||||
string: NSTemporaryDirectory()
|
|
||||||
)
|
|
||||||
.appendingPathComponent("tmp-\(Int.random(in: 0 ... .max))"))
|
|
||||||
|
|
||||||
let testFileManager = FileManager()
|
let testFileManager = FileManager()
|
||||||
|
var testTempDirectory: URL!
|
||||||
var dbData: URL! = nil
|
var dbData: URL! = nil
|
||||||
var paramDestination: URL! = nil
|
var paramDestination: URL! = nil
|
||||||
var network = ZcashNetworkBuilder.network(for: .testnet)
|
var network = ZcashNetworkBuilder.network(for: .testnet)
|
||||||
|
@ -26,8 +21,9 @@ class WalletTests: XCTestCase {
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
try super.setUpWithError()
|
try super.setUpWithError()
|
||||||
|
testTempDirectory = Environment.uniqueTestTempDirectory
|
||||||
dbData = try __dataDbURL()
|
dbData = try __dataDbURL()
|
||||||
try self.testFileManager.createDirectory(at: self.testTempDirectory, withIntermediateDirectories: false)
|
try self.testFileManager.createDirectory(at: testTempDirectory, withIntermediateDirectories: false)
|
||||||
paramDestination = try __documentsDirectory().appendingPathComponent("parameters")
|
paramDestination = try __documentsDirectory().appendingPathComponent("parameters")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,17 +32,17 @@ class WalletTests: XCTestCase {
|
||||||
if testFileManager.fileExists(atPath: dbData.absoluteString) {
|
if testFileManager.fileExists(atPath: dbData.absoluteString) {
|
||||||
try testFileManager.trashItem(at: dbData, resultingItemURL: nil)
|
try testFileManager.trashItem(at: dbData, resultingItemURL: nil)
|
||||||
}
|
}
|
||||||
try? self.testFileManager.removeItem(at: self.testTempDirectory)
|
try? self.testFileManager.removeItem(at: testTempDirectory)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testWalletInitialization() async throws {
|
func testWalletInitialization() async throws {
|
||||||
let derivationTool = DerivationTool(networkType: network.networkType)
|
let derivationTool = TestsData(networkType: network.networkType).derivationTools
|
||||||
let ufvk = try derivationTool.deriveUnifiedSpendingKey(seed: seedData.bytes, accountIndex: 0)
|
let spendingKey = try await derivationTool.deriveUnifiedSpendingKey(seed: seedData.bytes, accountIndex: 0)
|
||||||
.map({ try derivationTool.deriveUnifiedFullViewingKey(from: $0) })
|
let viewingKey = try await derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
|
|
||||||
let wallet = Initializer(
|
let wallet = Initializer(
|
||||||
cacheDbURL: nil,
|
cacheDbURL: nil,
|
||||||
fsBlockDbRoot: self.testTempDirectory,
|
fsBlockDbRoot: testTempDirectory,
|
||||||
dataDbURL: try __dataDbURL(),
|
dataDbURL: try __dataDbURL(),
|
||||||
pendingDbURL: try TestDbBuilder.pendingTransactionsDbURL(),
|
pendingDbURL: try TestDbBuilder.pendingTransactionsDbURL(),
|
||||||
endpoint: LightWalletEndpointBuilder.default,
|
endpoint: LightWalletEndpointBuilder.default,
|
||||||
|
@ -58,7 +54,7 @@ class WalletTests: XCTestCase {
|
||||||
|
|
||||||
let synchronizer = SDKSynchronizer(initializer: wallet)
|
let synchronizer = SDKSynchronizer(initializer: wallet)
|
||||||
do {
|
do {
|
||||||
guard case .success = try await synchronizer.prepare(with: seedData.bytes, viewingKeys: [ufvk], walletBirthday: 663194) else {
|
guard case .success = try await synchronizer.prepare(with: seedData.bytes, viewingKeys: [viewingKey], walletBirthday: 663194) else {
|
||||||
XCTFail("Failed to initDataDb. Expected `.success` got: `.seedRequired`")
|
XCTFail("Failed to initDataDb. Expected `.success` got: `.seedRequired`")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,8 @@ import XCTest
|
||||||
|
|
||||||
class ZcashRustBackendTests: XCTestCase {
|
class ZcashRustBackendTests: XCTestCase {
|
||||||
var dbData: URL!
|
var dbData: URL!
|
||||||
|
var rustBackend: ZcashRustBackendWelding!
|
||||||
var dataDbHandle = TestDbHandle(originalDb: TestDbBuilder.prePopulatedDataDbURL()!)
|
var dataDbHandle = TestDbHandle(originalDb: TestDbBuilder.prePopulatedDataDbURL()!)
|
||||||
|
|
||||||
let spendingKey = """
|
let spendingKey = """
|
||||||
secret-extended-key-test1qvpevftsqqqqpqy52ut2vv24a2qh7nsukew7qg9pq6djfwyc3xt5vaxuenshp2hhspp9qmqvdh0gs2ljpwxders5jkwgyhgln0drjqaguaenfhehz4esdl4k\
|
secret-extended-key-test1qvpevftsqqqqpqy52ut2vv24a2qh7nsukew7qg9pq6djfwyc3xt5vaxuenshp2hhspp9qmqvdh0gs2ljpwxders5jkwgyhgln0drjqaguaenfhehz4esdl4k\
|
||||||
wlm5t9q0l6wmzcrvcf5ed6dqzvct3e2ge7f6qdvzhp02m7sp5a0qjssrwpdh7u6tq89hl3wchuq8ljq8r8rwd6xdwh3nry9at80z7amnj3s6ah4jevnvfr08gxpws523z95g6dmn4wm6l3658\
|
wlm5t9q0l6wmzcrvcf5ed6dqzvct3e2ge7f6qdvzhp02m7sp5a0qjssrwpdh7u6tq89hl3wchuq8ljq8r8rwd6xdwh3nry9at80z7amnj3s6ah4jevnvfr08gxpws523z95g6dmn4wm6l3658\
|
||||||
|
@ -24,23 +24,27 @@ class ZcashRustBackendTests: XCTestCase {
|
||||||
let zpend: Int = 500_000
|
let zpend: Int = 500_000
|
||||||
|
|
||||||
let networkType = NetworkType.testnet
|
let networkType = NetworkType.testnet
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
super.setUp()
|
super.setUp()
|
||||||
|
|
||||||
dbData = try! __dataDbURL()
|
dbData = try! __dataDbURL()
|
||||||
try? dataDbHandle.setUp()
|
try? dataDbHandle.setUp()
|
||||||
|
|
||||||
|
rustBackend = ZcashRustBackend.makeForTests(dbData: dbData, fsBlockDbRoot: Environment.uniqueTestTempDirectory, networkType: .testnet)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
override func tearDown() {
|
||||||
super.tearDown()
|
super.tearDown()
|
||||||
try? FileManager.default.removeItem(at: dbData!)
|
try? FileManager.default.removeItem(at: dbData!)
|
||||||
dataDbHandle.dispose()
|
dataDbHandle.dispose()
|
||||||
|
rustBackend = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testInitWithShortSeedAndFail() async throws {
|
func testInitWithShortSeedAndFail() async throws {
|
||||||
let seed = "testreferencealice"
|
let seed = "testreferencealice"
|
||||||
|
|
||||||
let dbInit = try await ZcashRustBackend.initDataDb(dbData: self.dbData!, seed: nil, networkType: self.networkType)
|
let dbInit = try await rustBackend.initDataDb(seed: nil)
|
||||||
|
|
||||||
guard case .success = dbInit else {
|
guard case .success = dbInit else {
|
||||||
XCTFail("Failed to initDataDb. Expected `.success` got: \(String(describing: dbInit))")
|
XCTFail("Failed to initDataDb. Expected `.success` got: \(String(describing: dbInit))")
|
||||||
|
@ -48,76 +52,64 @@ class ZcashRustBackendTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
_ = try await ZcashRustBackend.createAccount(dbData: dbData!, seed: Array(seed.utf8), networkType: networkType)
|
_ = try await rustBackend.createAccount(seed: Array(seed.utf8))
|
||||||
XCTFail("createAccount should fail here.")
|
XCTFail("createAccount should fail here.")
|
||||||
} catch { }
|
} catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
func testIsValidTransparentAddressFalse() {
|
func testIsValidTransparentAddressFalse() {
|
||||||
XCTAssertFalse(
|
XCTAssertFalse(
|
||||||
ZcashRustBackend.isValidTransparentAddress(
|
ZcashKeyDerivationBackend(networkType: networkType).isValidTransparentAddress(
|
||||||
"ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc",
|
"ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc"
|
||||||
networkType: networkType
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testIsValidTransparentAddressTrue() {
|
func testIsValidTransparentAddressTrue() {
|
||||||
XCTAssertTrue(
|
XCTAssertTrue(
|
||||||
ZcashRustBackend.isValidTransparentAddress(
|
ZcashKeyDerivationBackend(networkType: networkType).isValidTransparentAddress(
|
||||||
"tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7",
|
"tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7"
|
||||||
networkType: networkType
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testIsValidSaplingAddressTrue() {
|
func testIsValidSaplingAddressTrue() {
|
||||||
XCTAssertTrue(
|
XCTAssertTrue(
|
||||||
ZcashRustBackend.isValidSaplingAddress(
|
ZcashKeyDerivationBackend(networkType: networkType).isValidSaplingAddress(
|
||||||
"ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc",
|
"ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc"
|
||||||
networkType: networkType
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testIsValidSaplingAddressFalse() {
|
func testIsValidSaplingAddressFalse() {
|
||||||
XCTAssertFalse(
|
XCTAssertFalse(
|
||||||
ZcashRustBackend.isValidSaplingAddress(
|
ZcashKeyDerivationBackend(networkType: networkType).isValidSaplingAddress(
|
||||||
"tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7",
|
"tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7"
|
||||||
networkType: networkType
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testListTransparentReceivers() async throws {
|
func testListTransparentReceivers() async throws {
|
||||||
let testVector = [TestVector](TestVector.testVectors![0 ... 2])
|
let testVector = [TestVector](TestVector.testVectors![0 ... 2])
|
||||||
let network = NetworkType.mainnet
|
|
||||||
let tempDBs = TemporaryDbBuilder.build()
|
let tempDBs = TemporaryDbBuilder.build()
|
||||||
let seed = testVector[0].root_seed!
|
let seed = testVector[0].root_seed!
|
||||||
|
rustBackend = ZcashRustBackend.makeForTests(dbData: tempDBs.dataDB, fsBlockDbRoot: Environment.uniqueTestTempDirectory, networkType: .mainnet)
|
||||||
|
|
||||||
try? FileManager.default.removeItem(at: tempDBs.dataDB)
|
try? FileManager.default.removeItem(at: tempDBs.dataDB)
|
||||||
|
|
||||||
let initResult = try await ZcashRustBackend.initDataDb(
|
let initResult = try await rustBackend.initDataDb(seed: seed)
|
||||||
dbData: tempDBs.dataDB,
|
|
||||||
seed: seed,
|
|
||||||
networkType: network
|
|
||||||
)
|
|
||||||
XCTAssertEqual(initResult, .success)
|
XCTAssertEqual(initResult, .success)
|
||||||
|
|
||||||
let usk = try await ZcashRustBackend.createAccount(
|
let usk = try await rustBackend.createAccount(seed: seed)
|
||||||
dbData: tempDBs.dataDB,
|
|
||||||
seed: seed,
|
|
||||||
networkType: network
|
|
||||||
)
|
|
||||||
XCTAssertEqual(usk.account, 0)
|
XCTAssertEqual(usk.account, 0)
|
||||||
|
|
||||||
let expectedReceivers = try testVector.map {
|
let expectedReceivers = try testVector.map {
|
||||||
UnifiedAddress(validatedEncoding: $0.unified_addr!)
|
UnifiedAddress(validatedEncoding: $0.unified_addr!, networkType: .mainnet)
|
||||||
}
|
}
|
||||||
.map { try $0.transparentReceiver() }
|
.map { try $0.transparentReceiver() }
|
||||||
|
|
||||||
let expectedUAs = testVector.map {
|
let expectedUAs = testVector.map {
|
||||||
UnifiedAddress(validatedEncoding: $0.unified_addr!)
|
UnifiedAddress(validatedEncoding: $0.unified_addr!, networkType: .mainnet)
|
||||||
}
|
}
|
||||||
|
|
||||||
guard expectedReceivers.count >= 2 else {
|
guard expectedReceivers.count >= 2 else {
|
||||||
|
@ -127,19 +119,11 @@ class ZcashRustBackendTests: XCTestCase {
|
||||||
var uAddresses: [UnifiedAddress] = []
|
var uAddresses: [UnifiedAddress] = []
|
||||||
for i in 0...2 {
|
for i in 0...2 {
|
||||||
uAddresses.append(
|
uAddresses.append(
|
||||||
try await ZcashRustBackend.getCurrentAddress(
|
try await rustBackend.getCurrentAddress(account: 0)
|
||||||
dbData: tempDBs.dataDB,
|
|
||||||
account: 0,
|
|
||||||
networkType: network
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if i < 2 {
|
if i < 2 {
|
||||||
_ = try await ZcashRustBackend.getNextAvailableAddress(
|
_ = try await rustBackend.getNextAvailableAddress(account: 0)
|
||||||
dbData: tempDBs.dataDB,
|
|
||||||
account: 0,
|
|
||||||
networkType: network
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,11 +132,7 @@ class ZcashRustBackendTests: XCTestCase {
|
||||||
expectedUAs
|
expectedUAs
|
||||||
)
|
)
|
||||||
|
|
||||||
let actualReceivers = try await ZcashRustBackend.listTransparentReceivers(
|
let actualReceivers = try await rustBackend.listTransparentReceivers(account: 0)
|
||||||
dbData: tempDBs.dataDB,
|
|
||||||
account: 0,
|
|
||||||
networkType: network
|
|
||||||
)
|
|
||||||
|
|
||||||
XCTAssertEqual(
|
XCTAssertEqual(
|
||||||
expectedReceivers.sorted(),
|
expectedReceivers.sorted(),
|
||||||
|
@ -163,7 +143,7 @@ class ZcashRustBackendTests: XCTestCase {
|
||||||
func testGetMetadataFromAddress() throws {
|
func testGetMetadataFromAddress() throws {
|
||||||
let recipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a"
|
let recipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a"
|
||||||
|
|
||||||
let metadata = ZcashRustBackend.getAddressMetadata(recipientAddress)
|
let metadata = ZcashKeyDerivationBackend.getAddressMetadata(recipientAddress)
|
||||||
|
|
||||||
XCTAssertEqual(metadata?.networkType, .mainnet)
|
XCTAssertEqual(metadata?.networkType, .mainnet)
|
||||||
XCTAssertEqual(metadata?.addressType, .sapling)
|
XCTAssertEqual(metadata?.addressType, .sapling)
|
||||||
|
|
|
@ -26,6 +26,8 @@ class SynchronizerTests: XCTestCase {
|
||||||
var coordinator: TestCoordinator!
|
var coordinator: TestCoordinator!
|
||||||
var cancellables: [AnyCancellable] = []
|
var cancellables: [AnyCancellable] = []
|
||||||
var sdkSynchronizerSyncStatusHandler: SDKSynchronizerSyncStatusHandler! = SDKSynchronizerSyncStatusHandler()
|
var sdkSynchronizerSyncStatusHandler: SDKSynchronizerSyncStatusHandler! = SDKSynchronizerSyncStatusHandler()
|
||||||
|
var rustBackend: ZcashRustBackendWelding!
|
||||||
|
var testTempDirectory: URL!
|
||||||
|
|
||||||
let seedPhrase = """
|
let seedPhrase = """
|
||||||
wish puppy smile loan doll curve hole maze file ginger hair nose key relax knife witness cannon grab despair throw review deal slush frame
|
wish puppy smile loan doll curve hole maze file ginger hair nose key relax knife witness cannon grab despair throw review deal slush frame
|
||||||
|
@ -33,11 +35,19 @@ class SynchronizerTests: XCTestCase {
|
||||||
|
|
||||||
var birthday: BlockHeight = 1_730_000
|
var birthday: BlockHeight = 1_730_000
|
||||||
|
|
||||||
|
override func setUp() async throws {
|
||||||
|
try await super.setUp()
|
||||||
|
testTempDirectory = Environment.uniqueTestTempDirectory
|
||||||
|
rustBackend = ZcashRustBackend.makeForTests(fsBlockDbRoot: testTempDirectory, networkType: .mainnet)
|
||||||
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
override func tearDown() {
|
||||||
super.tearDown()
|
super.tearDown()
|
||||||
coordinator = nil
|
coordinator = nil
|
||||||
cancellables = []
|
cancellables = []
|
||||||
sdkSynchronizerSyncStatusHandler = nil
|
sdkSynchronizerSyncStatusHandler = nil
|
||||||
|
rustBackend = nil
|
||||||
|
testTempDirectory = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testHundredBlocksSync() async throws {
|
func testHundredBlocksSync() async throws {
|
||||||
|
@ -47,11 +57,11 @@ class SynchronizerTests: XCTestCase {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let seedBytes = [UInt8](seedData)
|
let seedBytes = [UInt8](seedData)
|
||||||
let spendingKey = try derivationTool.deriveUnifiedSpendingKey(
|
let spendingKey = try await derivationTool.deriveUnifiedSpendingKey(
|
||||||
seed: seedBytes,
|
seed: seedBytes,
|
||||||
accountIndex: 0
|
accountIndex: 0
|
||||||
)
|
)
|
||||||
let ufvk = try derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
let ufvk = try await derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
let network = ZcashNetworkBuilder.network(for: .mainnet)
|
let network = ZcashNetworkBuilder.network(for: .mainnet)
|
||||||
let endpoint = LightWalletEndpoint(address: "lightwalletd.electriccoin.co", port: 9067, secure: true)
|
let endpoint = LightWalletEndpoint(address: "lightwalletd.electriccoin.co", port: 9067, secure: true)
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ class CompactBlockProcessorEventHandler {
|
||||||
|
|
||||||
func subscribe(to blockProcessor: CompactBlockProcessor, expectations: [EventIdentifier: XCTestExpectation]) async {
|
func subscribe(to blockProcessor: CompactBlockProcessor, expectations: [EventIdentifier: XCTestExpectation]) async {
|
||||||
let closure: CompactBlockProcessor.EventClosure = { event in
|
let closure: CompactBlockProcessor.EventClosure = { event in
|
||||||
|
print("Received event: \(event.identifier)")
|
||||||
expectations[event.identifier]?.fulfill()
|
expectations[event.identifier]?.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
import Combine
|
||||||
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
{% macro methodName method%}{%if method|annotated:"mockedName" %}{{ method.annotations.mockedName }}{% else %}{% call swiftifyMethodName method.selectorName %}{% endif %}{% endmacro %}
|
||||||
|
{% macro swiftifyMethodName name %}{{ name | replace:"(","_" | replace:")","" | replace:":","_" | replace:"`","" | snakeToCamelCase | lowerFirstWord }}{% endmacro %}
|
||||||
|
{% macro methodNameUpper method%}{%if method|annotated:"mockedName" %}{{ method.annotations.mockedName }}{% else %}{% call swiftifyMethodNameUpper method.selectorName %}{% endif %}{% endmacro %}
|
||||||
|
{% macro swiftifyMethodNameUpper name %}{{ name | replace:"(","_" | replace:")","" | replace:":","_" | replace:"`","" | snakeToCamelCase | upperFirstLetter }}{% endmacro %}
|
||||||
|
{% macro methodThrowableErrorDeclaration method type %}
|
||||||
|
{% if method.isStatic %}static {% endif %}var {% call methodName method %}ThrowableError: Error?
|
||||||
|
{% call methodMockPropertySetter method type "ThrowableError" "Error?" %}
|
||||||
|
{% endmacro %}
|
||||||
|
{% macro methodMockPropertySetter method type postfix propertyType %}
|
||||||
|
{% if type|annotated:"mockActor" %}{% if not method.isStatic %}
|
||||||
|
func set{% call methodNameUpper method %}{{ postfix }}(_ param: {{ propertyType }}) async {
|
||||||
|
{% call methodName method %}{{ postfix }} = param
|
||||||
|
}
|
||||||
|
{% endif %}{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
{% macro methodThrowableErrorUsage method %}
|
||||||
|
if let error = {% if method.isStatic %}Self.{% endif %}{% call methodName method %}ThrowableError {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
{% endmacro %}
|
||||||
|
{% macro methodReceivedParameters method %}
|
||||||
|
{%if method.parameters.count == 1 %}
|
||||||
|
{% if method.isStatic %}Self.{% endif %}{% call methodName method %}Received{% for param in method.parameters %}{{ param.name|upperFirstLetter }} = {{ param.name }}{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
{% if not method.parameters.count == 0 %}
|
||||||
|
{% if method.isStatic %}Self.{% endif %}{% call methodName method %}ReceivedArguments = ({% for param in method.parameters %}{{ param.name }}: {{ param.name }}{% if not forloop.last%}, {% endif %}{% endfor %})
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
{% macro methodClosureName method %}{% call methodName method %}Closure{% endmacro %}
|
||||||
|
{% macro paramTypeName param, method %}{% if method.annotations[param.name] %}{{method.annotations[param.name]}}{% else %}{{ param.typeName }}{% endif %}{% endmacro %}
|
||||||
|
{% macro unwrappedParamTypeName param, method %}{% if method.annotations[param.name] %}{{method.annotations[param.name]}}{% else %}{{ param.typeName.unwrappedTypeName }}{% endif %}{% endmacro %}
|
||||||
|
{% macro closureType method type %}({% for param in method.parameters %}{% call paramTypeName param, method %}{% if not forloop.last %}, {% endif %}{% endfor %}) {% if method.isAsync %}async {% endif %}{% if method.throws %}throws {% endif %}-> {% if method.isInitializer %}Void{% else %}{{ method.returnTypeName }}{% endif %}{% endmacro %}
|
||||||
|
{% macro methodClosureDeclaration method type %}
|
||||||
|
{% if method.isStatic %}static {% endif %}var {% call methodClosureName method %}: ({% call closureType method type %})?
|
||||||
|
{% if type|annotated:"mockActor" %}{% if not method.isStatic %}
|
||||||
|
func set{% call methodNameUpper method %}Closure(_ param: ({% call closureType method type %})?) async {
|
||||||
|
{% call methodName method %}Closure = param
|
||||||
|
}
|
||||||
|
{% endif %}{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
{% macro methodClosureCallParameters method %}{% for param in method.parameters %}{{ param.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endmacro %}
|
||||||
|
{% macro mockMethod method type %}
|
||||||
|
{% if method|!annotated:"skipAutoMock" %}
|
||||||
|
// MARK: - {{ method.shortName }}
|
||||||
|
|
||||||
|
{% if ((type|annotated:"mockActor") and (method.isAsync) or (method.isStatic)) or (not type|annotated:"mockActor") %}
|
||||||
|
{% if method.throws %}
|
||||||
|
{% call methodThrowableErrorDeclaration method type %}
|
||||||
|
{% endif %}
|
||||||
|
{% if not method.isInitializer %}
|
||||||
|
{% if method.isStatic %}static {% endif %}var {% call methodName method %}CallsCount = 0
|
||||||
|
{% if method.isStatic %}static {% endif %}var {% call methodName method %}Called: Bool {
|
||||||
|
return {% if method.isStatic %}Self.{% endif %}{% call methodName method %}CallsCount > 0
|
||||||
|
}
|
||||||
|
{% endif %}
|
||||||
|
{% if method.parameters.count == 1 %}
|
||||||
|
{% if method.isStatic %}static {% endif %}var {% call methodName method %}Received{% for param in method.parameters %}{{ param.name|upperFirstLetter }}: {% if param.isClosure %}({% endif %}{% call unwrappedParamTypeName param, method %}{% if param.isClosure %}){% endif %}?{% endfor %}
|
||||||
|
{% else %}{% if not method.parameters.count == 0 %}
|
||||||
|
{% if method.isStatic %}static {% endif %}var {% call methodName method %}ReceivedArguments: ({% for param in method.parameters %}{{ param.name }}: {% if param.typeAttributes.escaping %}{% call unwrappedParamTypeName param, method %}{% else %}{% call paramTypeName param, method %}{% endif %}{% if not forloop.last %}, {% endif %}{% endfor %})?
|
||||||
|
{% endif %}{% endif %}
|
||||||
|
{% if not method.returnTypeName.isVoid and not method.isInitializer %}
|
||||||
|
{% if method.isStatic %}static {% endif %}var {% call methodName method %}ReturnValue: {{ method.returnTypeName }}{{ '!' if not method.isOptionalReturnType }}
|
||||||
|
{% call methodMockPropertySetter method type "ReturnValue" method.returnTypeName %}
|
||||||
|
{% endif %}
|
||||||
|
{% call methodClosureDeclaration method type %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if method.isInitializer %}
|
||||||
|
required {{ method.name }} {
|
||||||
|
{% call methodReceivedParameters method %}
|
||||||
|
{% call methodClosureName method %}?({% call methodClosureCallParameters method %})
|
||||||
|
}
|
||||||
|
{% else %}
|
||||||
|
{% if (not method.isAsync) and (not method.isStatic) and (type|annotated:"mockActor") %}nonisolated {% endif %}{% if method.isStatic %}static {% endif %}func {{ method.name }}{% if method.isAsync %} async{% endif %}{% if method.throws %} throws{% endif %}{% if not method.returnTypeName.isVoid %} -> {{ method.returnTypeName }}{% endif %} {
|
||||||
|
{% if ((type|annotated:"mockActor") and ((method.isAsync) or (method.isStatic))) or (not type|annotated:"mockActor") %}
|
||||||
|
{% if method.throws %}
|
||||||
|
{% call methodThrowableErrorUsage method %}
|
||||||
|
{% endif %}
|
||||||
|
{% if method.isStatic %}Self.{% endif %}{% call methodName method %}CallsCount += 1
|
||||||
|
{% call methodReceivedParameters method %}
|
||||||
|
{% if method.returnTypeName.isVoid %}
|
||||||
|
{% if method.throws %}try {% endif %}{% if method.isAsync %}await {% endif %}{% call methodClosureName method %}?({% call methodClosureCallParameters method %})
|
||||||
|
{% else %}
|
||||||
|
if let closure = {% if method.isStatic %}Self.{% endif %}{% call methodClosureName method %} {
|
||||||
|
return {% if method.throws %}try {% endif %}{% if method.isAsync %}await {% endif %}closure({% call methodClosureCallParameters method %})
|
||||||
|
} else {
|
||||||
|
return {% if method.isStatic %}Self.{% endif %}{% call methodName method %}ReturnValue
|
||||||
|
}
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% if method.throws %}try {% endif %}{% call methodClosureName method %}!({% call methodClosureCallParameters method %})
|
||||||
|
{% endif %}
|
||||||
|
}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
{% macro mockOptionalVariable variable %}
|
||||||
|
var {% call mockedVariableName variable %}: {{ variable.typeName }}
|
||||||
|
{% endmacro %}
|
||||||
|
{% macro mockNonOptionalArrayOrDictionaryVariable variable %}
|
||||||
|
var {% call mockedVariableName variable %}: {{ variable.typeName }} {
|
||||||
|
get{% if variable.isAsync %} async{% endif %} { return {% call underlyingMockedVariableName variable %} }
|
||||||
|
}
|
||||||
|
var {% call underlyingMockedVariableName variable %}: {{ variable.typeName }} = {% if variable.isArray %}[]{% elif variable.isDictionary %}[:]{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
{% macro mockNonOptionalVariable variable %}
|
||||||
|
var {% call mockedVariableName variable %}: {{ variable.typeName }} {
|
||||||
|
get { return {% call underlyingMockedVariableName variable %} }
|
||||||
|
}
|
||||||
|
var {% call underlyingMockedVariableName variable %}: {% if variable.typeName.isClosure %}({{ variable.typeName }})!{% else %}{{ variable.typeName }}!{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro underlyingMockedVariableName variable %}underlying{{ variable.name|upperFirstLetter }}{% endmacro %}
|
||||||
|
{% macro initialMockedVariableValue variable %}initial{{ variable.name|upperFirstLetter }}{% endmacro %}
|
||||||
|
{% macro mockedVariableName variable %}{{ variable.name }}{% endmacro %}
|
||||||
|
|
||||||
|
// MARK: - AutoMockable protocols
|
||||||
|
{% for type in types.protocols where type.based.AutoMockable or type|annotated:"AutoMockable" %}{% if type.name != "AutoMockable" %}
|
||||||
|
{% if type|annotated:"moduleName" %}
|
||||||
|
/// Imported from {{ type.annotations.moduleName }} module
|
||||||
|
{% endif %}
|
||||||
|
{% if type|annotated:"targetOS" %}
|
||||||
|
#if os({{ type.annotations.targetOS }})
|
||||||
|
{% endif %}
|
||||||
|
{% if type|annotated:"mockActor" %}actor {% else %}class {% endif %}{{ type.name }}Mock: {% if type|annotated:"baseClass" %}{{ type.annotations.baseClass }}, {% endif %}{% if type|annotated:"moduleName" %}{{ type.annotations.moduleName }}.{% endif %}{{ type.name }} {
|
||||||
|
|
||||||
|
{% for method in type.allMethods|!definedInExtension %}
|
||||||
|
{% if (not method.isAsync) and (not method.isStatic) and (type|annotated:"mockActor") %}
|
||||||
|
nonisolated let {% call methodName method %}Closure: ({% call closureType method type %})?
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
init(
|
||||||
|
{% for method in type.allMethods|!definedInExtension where ((not method.isAsync) and (not method.isStatic) and (type|annotated:"mockActor")) %}
|
||||||
|
{% call methodName method %}Closure: ({% call closureType method type %})? = nil{% if not forloop.last %},{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
) {
|
||||||
|
{% for method in type.allMethods|!definedInExtension %}
|
||||||
|
{% if (not method.isAsync) and (not method.isStatic) and (type|annotated:"mockActor") %}
|
||||||
|
self.{% call methodName method %}Closure = {% call methodName method %}Closure
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
}
|
||||||
|
{% for variable in type.allVariables|!definedInExtension %}
|
||||||
|
{% if variable|!annotated:"skipAutoMock" %}
|
||||||
|
{% if variable.isOptional %}{% call mockOptionalVariable variable %}
|
||||||
|
{% elif variable.isArray or variable.isDictionary %}{% call mockNonOptionalArrayOrDictionaryVariable variable %}
|
||||||
|
{% else %}{% call mockNonOptionalVariable variable %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% for method in type.allMethods|!definedInExtension %}
|
||||||
|
{% call mockMethod method type %}
|
||||||
|
{% endfor %}
|
||||||
|
}
|
||||||
|
{% if type|annotated:"targetOS" %}
|
||||||
|
#endif
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}{% endfor %}
|
|
@ -0,0 +1,18 @@
|
||||||
|
//
|
||||||
|
// AutoMockable.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Michal Fousek on 04.04.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
/// This file defines types for which we need to generate mocks for usage in Player tests.
|
||||||
|
/// Each type must appear in appropriate section according to which module it comes from.
|
||||||
|
|
||||||
|
// sourcery:begin: AutoMockable
|
||||||
|
|
||||||
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
|
extension ZcashRustBackendWelding { }
|
||||||
|
extension Synchronizer { }
|
||||||
|
|
||||||
|
// sourcery:end:
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/zsh
|
||||||
|
|
||||||
|
sourcery_version=2.0.2
|
||||||
|
|
||||||
|
if which sourcery >/dev/null; then
|
||||||
|
if [[ $(sourcery --version) != $sourcery_version ]]; then
|
||||||
|
echo "warning: Compatible sourcery version not installed. Install sourcer $sourcery_version. Currently installed version is $(sourcery --version)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sourcery \
|
||||||
|
--sources ./ \
|
||||||
|
--sources ../../../Sources/ \
|
||||||
|
--templates AutoMockable.stencil \
|
||||||
|
--output GeneratedMocks/
|
||||||
|
|
||||||
|
else
|
||||||
|
echo "warning: sourcery not installed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,342 +49,128 @@ extension LightWalletServiceMockResponse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockRustBackend: ZcashRustBackendWelding {
|
class RustBackendMockHelper {
|
||||||
static var networkType = NetworkType.testnet
|
let rustBackendMock: ZcashRustBackendWeldingMock
|
||||||
static var mockDataDb = false
|
var mockValidateCombinedChainFailAfterAttempts: Int?
|
||||||
static var mockAcounts = false
|
|
||||||
static var mockError: RustWeldingError?
|
init(
|
||||||
static var mockLastError: String?
|
rustBackend: ZcashRustBackendWelding,
|
||||||
static var mockAccounts: [SaplingExtendedSpendingKey]?
|
consensusBranchID: Int32? = nil,
|
||||||
static var mockAddresses: [String]?
|
mockValidateCombinedChainSuccessRate: Float? = nil,
|
||||||
static var mockBalance: Int64?
|
mockValidateCombinedChainFailAfterAttempts: Int? = nil,
|
||||||
static var mockVerifiedBalance: Int64?
|
mockValidateCombinedChainKeepFailing: Bool = false,
|
||||||
static var mockMemo: String?
|
mockValidateCombinedChainFailureError: RustWeldingError = .chainValidationFailed(message: nil)
|
||||||
static var mockSentMemo: String?
|
) async {
|
||||||
static var mockValidateCombinedChainSuccessRate: Float?
|
self.mockValidateCombinedChainFailAfterAttempts = mockValidateCombinedChainFailAfterAttempts
|
||||||
static var mockValidateCombinedChainFailAfterAttempts: Int?
|
self.rustBackendMock = ZcashRustBackendWeldingMock(
|
||||||
static var mockValidateCombinedChainKeepFailing = false
|
consensusBranchIdForHeightClosure: { height in
|
||||||
static var mockValidateCombinedChainFailureHeight: BlockHeight = 0
|
if let consensusBranchID {
|
||||||
static var mockScanblocksSuccessRate: Float?
|
return consensusBranchID
|
||||||
static var mockCreateToAddress: Int64?
|
} else {
|
||||||
static var rustBackend = ZcashRustBackend.self
|
return try rustBackend.consensusBranchIdFor(height: height)
|
||||||
static var consensusBranchID: Int32?
|
}
|
||||||
static var writeBlocksMetadataResult: () throws -> Bool = { true }
|
}
|
||||||
static var rewindCacheToHeightResult: () -> Bool = { true }
|
)
|
||||||
static func latestCachedBlockHeight(fsBlockDbRoot: URL) async -> ZcashLightClientKit.BlockHeight {
|
await setupDefaultMock(
|
||||||
.empty()
|
rustBackend: rustBackend,
|
||||||
|
mockValidateCombinedChainSuccessRate: mockValidateCombinedChainSuccessRate,
|
||||||
|
mockValidateCombinedChainKeepFailing: mockValidateCombinedChainKeepFailing,
|
||||||
|
mockValidateCombinedChainFailureError: mockValidateCombinedChainFailureError
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func rewindCacheToHeight(fsBlockDbRoot: URL, height: Int32) async -> Bool {
|
private func setupDefaultMock(
|
||||||
rewindCacheToHeightResult()
|
rustBackend: ZcashRustBackendWelding,
|
||||||
}
|
mockValidateCombinedChainSuccessRate: Float? = nil,
|
||||||
|
mockValidateCombinedChainKeepFailing: Bool = false,
|
||||||
|
mockValidateCombinedChainFailureError: RustWeldingError = .chainValidationFailed(message: nil)
|
||||||
|
) async {
|
||||||
|
await rustBackendMock.setLatestCachedBlockHeightReturnValue(.empty())
|
||||||
|
await rustBackendMock.setInitBlockMetadataDbClosure() { }
|
||||||
|
await rustBackendMock.setWriteBlocksMetadataBlocksClosure() { _ in }
|
||||||
|
await rustBackendMock.setInitAccountsTableUfvksClosure() { _ in }
|
||||||
|
await rustBackendMock.setCreateToAddressUskToValueMemoReturnValue(-1)
|
||||||
|
await rustBackendMock.setShieldFundsUskMemoShieldingThresholdReturnValue(-1)
|
||||||
|
await rustBackendMock.setGetTransparentBalanceAccountReturnValue(0)
|
||||||
|
await rustBackendMock.setGetVerifiedBalanceAccountReturnValue(0)
|
||||||
|
await rustBackendMock.setListTransparentReceiversAccountReturnValue([])
|
||||||
|
await rustBackendMock.setGetCurrentAddressAccountThrowableError(KeyDerivationErrors.unableToDerive)
|
||||||
|
await rustBackendMock.setGetNextAvailableAddressAccountThrowableError(KeyDerivationErrors.unableToDerive)
|
||||||
|
await rustBackendMock.setShieldFundsUskMemoShieldingThresholdReturnValue(-1)
|
||||||
|
await rustBackendMock.setCreateAccountSeedThrowableError(KeyDerivationErrors.unableToDerive)
|
||||||
|
await rustBackendMock.setGetReceivedMemoIdNoteReturnValue(nil)
|
||||||
|
await rustBackendMock.setGetSentMemoIdNoteReturnValue(nil)
|
||||||
|
await rustBackendMock.setCreateToAddressUskToValueMemoReturnValue(-1)
|
||||||
|
await rustBackendMock.setInitDataDbSeedReturnValue(.seedRequired)
|
||||||
|
await rustBackendMock.setGetNearestRewindHeightHeightReturnValue(-1)
|
||||||
|
await rustBackendMock.setInitBlocksTableHeightHashTimeSaplingTreeClosure() { _, _, _, _ in }
|
||||||
|
await rustBackendMock.setPutUnspentTransparentOutputTxidIndexScriptValueHeightClosure() { _, _, _, _, _ in }
|
||||||
|
await rustBackendMock.setCreateToAddressUskToValueMemoReturnValue(-1)
|
||||||
|
await rustBackendMock.setCreateToAddressUskToValueMemoReturnValue(-1)
|
||||||
|
await rustBackendMock.setDecryptAndStoreTransactionTxBytesMinedHeightThrowableError(RustWeldingError.genericError(message: "mock fail"))
|
||||||
|
|
||||||
static func initBlockMetadataDb(fsBlockDbRoot: URL) async throws -> Bool {
|
await rustBackendMock.setInitDataDbSeedClosure() { seed in
|
||||||
true
|
return try await rustBackend.initDataDb(seed: seed)
|
||||||
}
|
|
||||||
|
|
||||||
static func writeBlocksMetadata(fsBlockDbRoot: URL, blocks: [ZcashLightClientKit.ZcashCompactBlock]) async throws -> Bool {
|
|
||||||
try writeBlocksMetadataResult()
|
|
||||||
}
|
|
||||||
|
|
||||||
static func initAccountsTable(dbData: URL, ufvks: [ZcashLightClientKit.UnifiedFullViewingKey], networkType: ZcashLightClientKit.NetworkType) async throws { }
|
|
||||||
|
|
||||||
static func createToAddress(dbData: URL, usk: ZcashLightClientKit.UnifiedSpendingKey, to address: String, value: Int64, memo: ZcashLightClientKit.MemoBytes?, spendParamsPath: String, outputParamsPath: String, networkType: ZcashLightClientKit.NetworkType) async -> Int64 {
|
|
||||||
-1
|
|
||||||
}
|
|
||||||
|
|
||||||
static func shieldFunds(
|
|
||||||
dbData: URL,
|
|
||||||
usk: ZcashLightClientKit.UnifiedSpendingKey,
|
|
||||||
memo: ZcashLightClientKit.MemoBytes?,
|
|
||||||
shieldingThreshold: Zatoshi,
|
|
||||||
spendParamsPath: String,
|
|
||||||
outputParamsPath: String,
|
|
||||||
networkType: ZcashLightClientKit.NetworkType
|
|
||||||
) async -> Int64 {
|
|
||||||
-1
|
|
||||||
}
|
|
||||||
|
|
||||||
static func getAddressMetadata(_ address: String) -> ZcashLightClientKit.AddressMetadata? {
|
|
||||||
nil
|
|
||||||
}
|
|
||||||
|
|
||||||
static func clearUtxos(dbData: URL, address: ZcashLightClientKit.TransparentAddress, sinceHeight: ZcashLightClientKit.BlockHeight, networkType: ZcashLightClientKit.NetworkType) async throws -> Int32 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
static func getTransparentBalance(dbData: URL, account: Int32, networkType: ZcashLightClientKit.NetworkType) async throws -> Int64 { 0 }
|
|
||||||
|
|
||||||
static func getVerifiedTransparentBalance(dbData: URL, account: Int32, networkType: ZcashLightClientKit.NetworkType) async throws -> Int64 { 0 }
|
|
||||||
|
|
||||||
static func listTransparentReceivers(dbData: URL, account: Int32, networkType: ZcashLightClientKit.NetworkType) async throws -> [ZcashLightClientKit.TransparentAddress] {
|
|
||||||
[]
|
|
||||||
}
|
|
||||||
|
|
||||||
static func deriveUnifiedFullViewingKey(from spendingKey: ZcashLightClientKit.UnifiedSpendingKey, networkType: ZcashLightClientKit.NetworkType) throws -> ZcashLightClientKit.UnifiedFullViewingKey {
|
|
||||||
throw KeyDerivationErrors.unableToDerive
|
|
||||||
}
|
|
||||||
|
|
||||||
static func deriveUnifiedSpendingKey(from seed: [UInt8], accountIndex: Int32, networkType: ZcashLightClientKit.NetworkType) throws -> ZcashLightClientKit.UnifiedSpendingKey {
|
|
||||||
throw KeyDerivationErrors.unableToDerive
|
|
||||||
}
|
|
||||||
|
|
||||||
static func getCurrentAddress(dbData: URL, account: Int32, networkType: ZcashLightClientKit.NetworkType) async throws -> ZcashLightClientKit.UnifiedAddress {
|
|
||||||
throw KeyDerivationErrors.unableToDerive
|
|
||||||
}
|
|
||||||
|
|
||||||
static func getNextAvailableAddress(dbData: URL, account: Int32, networkType: ZcashLightClientKit.NetworkType) async throws -> ZcashLightClientKit.UnifiedAddress {
|
|
||||||
throw KeyDerivationErrors.unableToDerive
|
|
||||||
}
|
|
||||||
|
|
||||||
static func getSaplingReceiver(for uAddr: ZcashLightClientKit.UnifiedAddress) throws -> ZcashLightClientKit.SaplingAddress {
|
|
||||||
throw KeyDerivationErrors.unableToDerive
|
|
||||||
}
|
|
||||||
|
|
||||||
static func getTransparentReceiver(for uAddr: ZcashLightClientKit.UnifiedAddress) throws -> ZcashLightClientKit.TransparentAddress {
|
|
||||||
throw KeyDerivationErrors.unableToDerive
|
|
||||||
}
|
|
||||||
|
|
||||||
static func shieldFunds(dbData: URL, usk: ZcashLightClientKit.UnifiedSpendingKey, memo: ZcashLightClientKit.MemoBytes, spendParamsPath: String, outputParamsPath: String, networkType: ZcashLightClientKit.NetworkType) async -> Int64 {
|
|
||||||
-1
|
|
||||||
}
|
|
||||||
|
|
||||||
static func receiverTypecodesOnUnifiedAddress(_ address: String) throws -> [UInt32] {
|
|
||||||
throw KeyDerivationErrors.receiverNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
static func createAccount(dbData: URL, seed: [UInt8], networkType: ZcashLightClientKit.NetworkType) async throws -> ZcashLightClientKit.UnifiedSpendingKey {
|
|
||||||
throw KeyDerivationErrors.unableToDerive
|
|
||||||
}
|
|
||||||
|
|
||||||
static func getReceivedMemo(dbData: URL, idNote: Int64, networkType: ZcashLightClientKit.NetworkType) async -> ZcashLightClientKit.Memo? { nil }
|
|
||||||
|
|
||||||
static func getSentMemo(dbData: URL, idNote: Int64, networkType: ZcashLightClientKit.NetworkType) async -> ZcashLightClientKit.Memo? { nil }
|
|
||||||
|
|
||||||
static func createToAddress(dbData: URL, usk: ZcashLightClientKit.UnifiedSpendingKey, to address: String, value: Int64, memo: ZcashLightClientKit.MemoBytes, spendParamsPath: String, outputParamsPath: String, networkType: ZcashLightClientKit.NetworkType) async -> Int64 {
|
|
||||||
-1
|
|
||||||
}
|
|
||||||
|
|
||||||
static func initDataDb(dbData: URL, seed: [UInt8]?, networkType: ZcashLightClientKit.NetworkType) async throws -> ZcashLightClientKit.DbInitResult {
|
|
||||||
.seedRequired
|
|
||||||
}
|
|
||||||
|
|
||||||
static func deriveSaplingAddressFromViewingKey(_ extfvk: ZcashLightClientKit.SaplingExtendedFullViewingKey, networkType: ZcashLightClientKit.NetworkType) throws -> ZcashLightClientKit.SaplingAddress {
|
|
||||||
throw RustWeldingError.unableToDeriveKeys
|
|
||||||
}
|
|
||||||
|
|
||||||
static func isValidSaplingExtendedSpendingKey(_ key: String, networkType: ZcashLightClientKit.NetworkType) -> Bool { false }
|
|
||||||
|
|
||||||
static func deriveSaplingExtendedFullViewingKeys(seed: [UInt8], accounts: Int32, networkType: ZcashLightClientKit.NetworkType) throws -> [ZcashLightClientKit.SaplingExtendedFullViewingKey]? {
|
|
||||||
nil
|
|
||||||
}
|
|
||||||
|
|
||||||
static func isValidUnifiedAddress(_ address: String, networkType: ZcashLightClientKit.NetworkType) -> Bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
static func deriveSaplingExtendedFullViewingKey(_ spendingKey: SaplingExtendedSpendingKey, networkType: ZcashLightClientKit.NetworkType) throws -> ZcashLightClientKit.SaplingExtendedFullViewingKey? {
|
|
||||||
nil
|
|
||||||
}
|
|
||||||
|
|
||||||
public func deriveViewingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [UnifiedFullViewingKey] { [] }
|
|
||||||
|
|
||||||
static func getNearestRewindHeight(dbData: URL, height: Int32, networkType: NetworkType) async -> Int32 { -1 }
|
|
||||||
|
|
||||||
static func network(dbData: URL, address: String, sinceHeight: BlockHeight, networkType: NetworkType) async throws -> Int32 { -1 }
|
|
||||||
|
|
||||||
static func initAccountsTable(dbData: URL, ufvks: [UnifiedFullViewingKey], networkType: NetworkType) async throws -> Bool { false }
|
|
||||||
|
|
||||||
static func putUnspentTransparentOutput(
|
|
||||||
dbData: URL,
|
|
||||||
txid: [UInt8],
|
|
||||||
index: Int,
|
|
||||||
script: [UInt8],
|
|
||||||
value: Int64,
|
|
||||||
height: BlockHeight,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws -> Bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
static func downloadedUtxoBalance(dbData: URL, address: String, networkType: NetworkType) async throws -> WalletBalance {
|
|
||||||
throw RustWeldingError.genericError(message: "unimplemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
static func createToAddress(
|
|
||||||
dbData: URL,
|
|
||||||
account: Int32,
|
|
||||||
extsk: String,
|
|
||||||
to address: String,
|
|
||||||
value: Int64,
|
|
||||||
memo: String?,
|
|
||||||
spendParamsPath: String,
|
|
||||||
outputParamsPath: String,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async -> Int64 {
|
|
||||||
-1
|
|
||||||
}
|
|
||||||
|
|
||||||
static func deriveTransparentAddressFromSeed(seed: [UInt8], account: Int, index: Int, networkType: NetworkType) throws -> TransparentAddress {
|
|
||||||
throw KeyDerivationErrors.unableToDerive
|
|
||||||
}
|
|
||||||
|
|
||||||
static func deriveUnifiedFullViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int32, networkType: NetworkType) throws -> [UnifiedFullViewingKey] {
|
|
||||||
throw KeyDerivationErrors.unableToDerive
|
|
||||||
}
|
|
||||||
|
|
||||||
static func isValidSaplingExtendedFullViewingKey(_ key: String, networkType: NetworkType) -> Bool { false }
|
|
||||||
|
|
||||||
static func isValidUnifiedFullViewingKey(_ ufvk: String, networkType: NetworkType) -> Bool { false }
|
|
||||||
|
|
||||||
static func deriveSaplingExtendedSpendingKeys(seed: [UInt8], accounts: Int32, networkType: NetworkType) throws -> [SaplingExtendedSpendingKey]? { nil }
|
|
||||||
|
|
||||||
static func consensusBranchIdFor(height: Int32, networkType: NetworkType) throws -> Int32 {
|
|
||||||
guard let consensus = consensusBranchID else {
|
|
||||||
return try rustBackend.consensusBranchIdFor(height: height, networkType: networkType)
|
|
||||||
}
|
}
|
||||||
return consensus
|
|
||||||
}
|
|
||||||
|
|
||||||
static func lastError() -> RustWeldingError? {
|
await rustBackendMock.setInitBlocksTableHeightHashTimeSaplingTreeClosure() { height, hash, time, saplingTree in
|
||||||
mockError ?? rustBackend.lastError()
|
|
||||||
}
|
|
||||||
|
|
||||||
static func getLastError() -> String? {
|
|
||||||
mockLastError ?? rustBackend.getLastError()
|
|
||||||
}
|
|
||||||
|
|
||||||
static func isValidSaplingAddress(_ address: String, networkType: NetworkType) -> Bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
static func isValidTransparentAddress(_ address: String, networkType: NetworkType) -> Bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
static func initDataDb(dbData: URL, networkType: NetworkType) async throws {
|
|
||||||
if !mockDataDb {
|
|
||||||
_ = try await rustBackend.initDataDb(dbData: dbData, seed: nil, networkType: networkType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static func initBlocksTable(
|
|
||||||
dbData: URL,
|
|
||||||
height: Int32,
|
|
||||||
hash: String,
|
|
||||||
time: UInt32,
|
|
||||||
saplingTree: String,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async throws {
|
|
||||||
if !mockDataDb {
|
|
||||||
try await rustBackend.initBlocksTable(
|
try await rustBackend.initBlocksTable(
|
||||||
dbData: dbData,
|
|
||||||
height: height,
|
height: height,
|
||||||
hash: hash,
|
hash: hash,
|
||||||
time: time,
|
time: time,
|
||||||
saplingTree: saplingTree,
|
saplingTree: saplingTree
|
||||||
networkType: networkType
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
await rustBackendMock.setGetBalanceAccountClosure() { account in
|
||||||
static func getBalance(dbData: URL, account: Int32, networkType: NetworkType) async throws -> Int64 {
|
return try await rustBackend.getBalance(account: account)
|
||||||
if let balance = mockBalance {
|
|
||||||
return balance
|
|
||||||
}
|
|
||||||
return try await rustBackend.getBalance(dbData: dbData, account: account, networkType: networkType)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func getVerifiedBalance(dbData: URL, account: Int32, networkType: NetworkType) async throws -> Int64 {
|
|
||||||
if let balance = mockVerifiedBalance {
|
|
||||||
return balance
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return try await rustBackend.getVerifiedBalance(dbData: dbData, account: account, networkType: networkType)
|
await rustBackendMock.setGetVerifiedBalanceAccountClosure() { account in
|
||||||
}
|
return try await rustBackend.getVerifiedBalance(account: account)
|
||||||
|
}
|
||||||
static func validateCombinedChain(fsBlockDbRoot: URL, dbData: URL, networkType: NetworkType, limit: UInt32 = 0) async -> Int32 {
|
|
||||||
if let rate = self.mockValidateCombinedChainSuccessRate {
|
await rustBackendMock.setValidateCombinedChainLimitClosure() { [weak self] limit in
|
||||||
if shouldSucceed(successRate: rate) {
|
guard let self else { throw RustWeldingError.genericError(message: "Self is nil") }
|
||||||
return await validationResult(fsBlockDbRoot: fsBlockDbRoot, dbData: dbData, networkType: networkType)
|
if let rate = mockValidateCombinedChainSuccessRate {
|
||||||
} else {
|
if Self.shouldSucceed(successRate: rate) {
|
||||||
return Int32(mockValidateCombinedChainFailureHeight)
|
return try await rustBackend.validateCombinedChain(limit: limit)
|
||||||
}
|
|
||||||
} else if let attempts = self.mockValidateCombinedChainFailAfterAttempts {
|
|
||||||
self.mockValidateCombinedChainFailAfterAttempts = attempts - 1
|
|
||||||
if attempts > 0 {
|
|
||||||
return await validationResult(fsBlockDbRoot: fsBlockDbRoot, dbData: dbData, networkType: networkType)
|
|
||||||
} else {
|
|
||||||
if attempts == 0 {
|
|
||||||
return Int32(mockValidateCombinedChainFailureHeight)
|
|
||||||
} else if attempts < 0 && mockValidateCombinedChainKeepFailing {
|
|
||||||
return Int32(mockValidateCombinedChainFailureHeight)
|
|
||||||
} else {
|
} else {
|
||||||
return await validationResult(fsBlockDbRoot: fsBlockDbRoot, dbData: dbData, networkType: networkType)
|
throw mockValidateCombinedChainFailureError
|
||||||
|
}
|
||||||
|
} else if let attempts = self.mockValidateCombinedChainFailAfterAttempts {
|
||||||
|
self.mockValidateCombinedChainFailAfterAttempts = attempts - 1
|
||||||
|
if attempts > 0 {
|
||||||
|
return try await rustBackend.validateCombinedChain(limit: limit)
|
||||||
|
} else {
|
||||||
|
if attempts == 0 {
|
||||||
|
throw mockValidateCombinedChainFailureError
|
||||||
|
} else if attempts < 0 && mockValidateCombinedChainKeepFailing {
|
||||||
|
throw mockValidateCombinedChainFailureError
|
||||||
|
} else {
|
||||||
|
return try await rustBackend.validateCombinedChain(limit: limit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
return await rustBackend.validateCombinedChain(fsBlockDbRoot: fsBlockDbRoot, dbData: dbData, networkType: networkType)
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func validationResult(fsBlockDbRoot: URL, dbData: URL, networkType: NetworkType) async -> Int32 {
|
|
||||||
if mockDataDb {
|
|
||||||
return -1
|
|
||||||
} else {
|
|
||||||
return await rustBackend.validateCombinedChain(fsBlockDbRoot: fsBlockDbRoot, dbData: dbData, networkType: networkType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static func rewindToHeight(dbData: URL, height: Int32, networkType: NetworkType) async -> Bool {
|
|
||||||
mockDataDb ? true : rustBackend.rewindToHeight(dbData: dbData, height: height, networkType: networkType)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func scanBlocks(fsBlockDbRoot: URL, dbData: URL, limit: UInt32, networkType: NetworkType) async -> Bool {
|
|
||||||
if let rate = mockScanblocksSuccessRate {
|
|
||||||
if shouldSucceed(successRate: rate) {
|
|
||||||
return mockDataDb ? true : await rustBackend.scanBlocks(fsBlockDbRoot: fsBlockDbRoot, dbData: dbData, networkType: networkType)
|
|
||||||
} else {
|
} else {
|
||||||
return false
|
return try await rustBackend.validateCombinedChain(limit: limit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return await rustBackend.scanBlocks(fsBlockDbRoot: fsBlockDbRoot, dbData: dbData, networkType: Self.networkType)
|
|
||||||
|
await rustBackendMock.setRewindToHeightHeightClosure() { height in
|
||||||
|
try await rustBackend.rewindToHeight(height: height)
|
||||||
|
}
|
||||||
|
|
||||||
|
await rustBackendMock.setRewindCacheToHeightHeightClosure() { _ in }
|
||||||
|
|
||||||
|
await rustBackendMock.setScanBlocksLimitClosure() { limit in
|
||||||
|
try await rustBackend.scanBlocks(limit: limit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func createToAddress(
|
private static func shouldSucceed(successRate: Float) -> Bool {
|
||||||
dbData: URL,
|
|
||||||
account: Int32,
|
|
||||||
extsk: String,
|
|
||||||
consensusBranchId: Int32,
|
|
||||||
to address: String,
|
|
||||||
value: Int64,
|
|
||||||
memo: String?,
|
|
||||||
spendParamsPath: String,
|
|
||||||
outputParamsPath: String,
|
|
||||||
networkType: NetworkType
|
|
||||||
) async -> Int64 {
|
|
||||||
-1
|
|
||||||
}
|
|
||||||
|
|
||||||
static func shouldSucceed(successRate: Float) -> Bool {
|
|
||||||
let random = Float.random(in: 0.0...1.0)
|
let random = Float.random(in: 0.0...1.0)
|
||||||
return random <= successRate
|
return random <= successRate
|
||||||
}
|
}
|
||||||
|
|
||||||
static func deriveExtendedFullViewingKey(_ spendingKey: String, networkType: NetworkType) throws -> String? {
|
|
||||||
nil
|
|
||||||
}
|
|
||||||
|
|
||||||
static func deriveExtendedFullViewingKeys(seed: String, accounts: Int32, networkType: NetworkType) throws -> [String]? {
|
|
||||||
nil
|
|
||||||
}
|
|
||||||
|
|
||||||
static func deriveExtendedSpendingKeys(seed: String, accounts: Int32, networkType: NetworkType) throws -> [String]? {
|
|
||||||
nil
|
|
||||||
}
|
|
||||||
|
|
||||||
static func decryptAndStoreTransaction(dbData: URL, txBytes: [UInt8], minedHeight: Int32, networkType: NetworkType) async -> Bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SaplingParamsSourceURL {
|
extension SaplingParamsSourceURL {
|
||||||
|
|
|
@ -1,174 +0,0 @@
|
||||||
//
|
|
||||||
// SynchronizerMock.swift
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Created by Michal Fousek on 20.03.2023.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Combine
|
|
||||||
import Foundation
|
|
||||||
@testable import ZcashLightClientKit
|
|
||||||
|
|
||||||
class SynchronizerMock: Synchronizer {
|
|
||||||
init() { }
|
|
||||||
|
|
||||||
var underlyingAlias: ZcashSynchronizerAlias! = nil
|
|
||||||
var alias: ZcashLightClientKit.ZcashSynchronizerAlias { underlyingAlias }
|
|
||||||
|
|
||||||
var underlyingStateStream: AnyPublisher<SynchronizerState, Never>! = nil
|
|
||||||
var stateStream: AnyPublisher<SynchronizerState, Never> { underlyingStateStream }
|
|
||||||
|
|
||||||
var underlyingLatestState: SynchronizerState! = nil
|
|
||||||
var latestState: SynchronizerState { underlyingLatestState }
|
|
||||||
|
|
||||||
var underlyingEventStream: AnyPublisher<SynchronizerEvent, Never>! = nil
|
|
||||||
var eventStream: AnyPublisher<SynchronizerEvent, Never> { underlyingEventStream }
|
|
||||||
|
|
||||||
var underlyingConnectionState: ConnectionState! = nil
|
|
||||||
var connectionState: ConnectionState { underlyingConnectionState }
|
|
||||||
|
|
||||||
let metrics = SDKMetrics()
|
|
||||||
|
|
||||||
var prepareWithSeedViewingKeysWalletBirthdayClosure: (
|
|
||||||
([UInt8]?, [UnifiedFullViewingKey], BlockHeight) async throws -> Initializer.InitializationResult
|
|
||||||
)! = nil
|
|
||||||
func prepare(
|
|
||||||
with seed: [UInt8]?,
|
|
||||||
viewingKeys: [UnifiedFullViewingKey],
|
|
||||||
walletBirthday: BlockHeight
|
|
||||||
) async throws -> Initializer.InitializationResult {
|
|
||||||
return try await prepareWithSeedViewingKeysWalletBirthdayClosure(seed, viewingKeys, walletBirthday)
|
|
||||||
}
|
|
||||||
|
|
||||||
var startRetryClosure: ((Bool) async throws -> Void)! = nil
|
|
||||||
func start(retry: Bool) async throws {
|
|
||||||
try await startRetryClosure(retry)
|
|
||||||
}
|
|
||||||
|
|
||||||
var stopClosure: (() async -> Void)! = nil
|
|
||||||
func stop() async {
|
|
||||||
await stopClosure()
|
|
||||||
}
|
|
||||||
|
|
||||||
var getSaplingAddressAccountIndexClosure: ((Int) async throws -> SaplingAddress)! = nil
|
|
||||||
func getSaplingAddress(accountIndex: Int) async throws -> SaplingAddress {
|
|
||||||
return try await getSaplingAddressAccountIndexClosure(accountIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
var getUnifiedAddressAccountIndexClosure: ((Int) async throws -> UnifiedAddress)! = nil
|
|
||||||
func getUnifiedAddress(accountIndex: Int) async throws -> UnifiedAddress {
|
|
||||||
return try await getUnifiedAddressAccountIndexClosure(accountIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
var getTransparentAddressAccountIndexClosure: ((Int) async throws -> TransparentAddress)! = nil
|
|
||||||
func getTransparentAddress(accountIndex: Int) async throws -> TransparentAddress {
|
|
||||||
return try await getTransparentAddressAccountIndexClosure(accountIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
var sendToAddressSpendingKeyZatoshiToAddressMemoClosure: (
|
|
||||||
(UnifiedSpendingKey, Zatoshi, Recipient, Memo?) async throws -> PendingTransactionEntity
|
|
||||||
)! = nil
|
|
||||||
func sendToAddress(spendingKey: UnifiedSpendingKey, zatoshi: Zatoshi, toAddress: Recipient, memo: Memo?) async throws -> PendingTransactionEntity {
|
|
||||||
return try await sendToAddressSpendingKeyZatoshiToAddressMemoClosure(spendingKey, zatoshi, toAddress, memo)
|
|
||||||
}
|
|
||||||
|
|
||||||
var shieldFundsSpendingKeyMemoShieldingThresholdClosure: ((UnifiedSpendingKey, Memo, Zatoshi) async throws -> PendingTransactionEntity)! = nil
|
|
||||||
func shieldFunds(spendingKey: UnifiedSpendingKey, memo: Memo, shieldingThreshold: Zatoshi) async throws -> PendingTransactionEntity {
|
|
||||||
return try await shieldFundsSpendingKeyMemoShieldingThresholdClosure(spendingKey, memo, shieldingThreshold)
|
|
||||||
}
|
|
||||||
|
|
||||||
var cancelSpendTransactionClosure: ((PendingTransactionEntity) async -> Bool)! = nil
|
|
||||||
func cancelSpend(transaction: PendingTransactionEntity) async -> Bool {
|
|
||||||
return await cancelSpendTransactionClosure(transaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
var underlyingPendingTransactions: [PendingTransactionEntity]! = nil
|
|
||||||
var pendingTransactions: [PendingTransactionEntity] {
|
|
||||||
get async { underlyingPendingTransactions }
|
|
||||||
}
|
|
||||||
|
|
||||||
var underlyingClearedTransactions: [ZcashTransaction.Overview]! = nil
|
|
||||||
var clearedTransactions: [ZcashTransaction.Overview] {
|
|
||||||
get async { underlyingClearedTransactions }
|
|
||||||
}
|
|
||||||
|
|
||||||
var underlyingSentTransactions: [ZcashTransaction.Sent]! = nil
|
|
||||||
var sentTransactions: [ZcashTransaction.Sent] {
|
|
||||||
get async { underlyingSentTransactions }
|
|
||||||
}
|
|
||||||
|
|
||||||
var underlyingReceivedTransactions: [ZcashTransaction.Received]! = nil
|
|
||||||
var receivedTransactions: [ZcashTransaction.Received] {
|
|
||||||
get async { underlyingReceivedTransactions }
|
|
||||||
}
|
|
||||||
|
|
||||||
var paginatedTransactionsOfKindClosure: ((TransactionKind) -> PaginatedTransactionRepository)! = nil
|
|
||||||
func paginatedTransactions(of kind: TransactionKind) -> PaginatedTransactionRepository {
|
|
||||||
return paginatedTransactionsOfKindClosure(kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
var getMemosForTransactionClosure: ((ZcashTransaction.Overview) async throws -> [Memo])! = nil
|
|
||||||
func getMemos(for transaction: ZcashTransaction.Overview) async throws -> [Memo] {
|
|
||||||
return try await getMemosForTransactionClosure(transaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
var getMemosForReceivedTransactionClosure: ((ZcashTransaction.Received) async throws -> [Memo])! = nil
|
|
||||||
func getMemos(for receivedTransaction: ZcashTransaction.Received) async throws -> [Memo] {
|
|
||||||
return try await getMemosForReceivedTransactionClosure(receivedTransaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
var getMemosForSentTransactionClosure: ((ZcashTransaction.Sent) async throws -> [Memo])! = nil
|
|
||||||
func getMemos(for sentTransaction: ZcashTransaction.Sent) async throws -> [Memo] {
|
|
||||||
return try await getMemosForSentTransactionClosure(sentTransaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
var getRecipientsForClearedTransactionClosure: ((ZcashTransaction.Overview) async -> [TransactionRecipient])! = nil
|
|
||||||
func getRecipients(for transaction: ZcashTransaction.Overview) async -> [TransactionRecipient] {
|
|
||||||
return await getRecipientsForClearedTransactionClosure(transaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
var getRecipientsForSentTransactionClosure: ((ZcashTransaction.Sent) async -> [TransactionRecipient])! = nil
|
|
||||||
func getRecipients(for transaction: ZcashTransaction.Sent) async -> [TransactionRecipient] {
|
|
||||||
return await getRecipientsForSentTransactionClosure(transaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
var allConfirmedTransactionsFromTransactionClosure: ((ZcashTransaction.Overview, Int) async throws -> [ZcashTransaction.Overview])! = nil
|
|
||||||
func allConfirmedTransactions(from transaction: ZcashTransaction.Overview, limit: Int) async throws -> [ZcashTransaction.Overview] {
|
|
||||||
return try await allConfirmedTransactionsFromTransactionClosure(transaction, limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
var latestHeightClosure: (() async throws -> BlockHeight)! = nil
|
|
||||||
func latestHeight() async throws -> BlockHeight {
|
|
||||||
return try await latestHeightClosure()
|
|
||||||
}
|
|
||||||
|
|
||||||
var refreshUTXOsAddressFromHeightClosure: ((TransparentAddress, BlockHeight) async throws -> RefreshedUTXOs)! = nil
|
|
||||||
func refreshUTXOs(address: TransparentAddress, from height: BlockHeight) async throws -> RefreshedUTXOs {
|
|
||||||
return try await refreshUTXOsAddressFromHeightClosure(address, height)
|
|
||||||
}
|
|
||||||
|
|
||||||
var getTransparentBalanceAccountIndexClosure: ((Int) async throws -> WalletBalance)! = nil
|
|
||||||
func getTransparentBalance(accountIndex: Int) async throws -> WalletBalance {
|
|
||||||
return try await getTransparentBalanceAccountIndexClosure(accountIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
var getShieldedBalanceAccountIndexClosure: ((Int) async throws -> Zatoshi)! = nil
|
|
||||||
func getShieldedBalance(accountIndex: Int) async throws -> Zatoshi {
|
|
||||||
try await getShieldedBalanceAccountIndexClosure(accountIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
var getShieldedVerifiedBalanceAccountIndexClosure: ((Int) async throws -> Zatoshi)! = nil
|
|
||||||
func getShieldedVerifiedBalance(accountIndex: Int) async throws -> Zatoshi {
|
|
||||||
try await getShieldedVerifiedBalanceAccountIndexClosure(accountIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
var rewindPolicyClosure: ((RewindPolicy) -> AnyPublisher<Void, Error>)! = nil
|
|
||||||
func rewind(_ policy: RewindPolicy) -> AnyPublisher<Void, Error> {
|
|
||||||
return rewindPolicyClosure(policy)
|
|
||||||
}
|
|
||||||
|
|
||||||
var wipeClosure: (() -> AnyPublisher<Void, Error>)! = nil
|
|
||||||
func wipe() -> AnyPublisher<Void, Error> {
|
|
||||||
return wipeClosure()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -52,56 +52,19 @@ class TestCoordinator {
|
||||||
singleCallTimeoutInMillis: 10000,
|
singleCallTimeoutInMillis: 10000,
|
||||||
streamingCallTimeoutInMillis: 1000000
|
streamingCallTimeoutInMillis: 1000000
|
||||||
)
|
)
|
||||||
|
|
||||||
convenience init(
|
init(
|
||||||
alias: ZcashSynchronizerAlias = .default,
|
alias: ZcashSynchronizerAlias = .default,
|
||||||
walletBirthday: BlockHeight,
|
walletBirthday: BlockHeight,
|
||||||
network: ZcashNetwork,
|
network: ZcashNetwork,
|
||||||
callPrepareInConstructor: Bool = true,
|
callPrepareInConstructor: Bool = true,
|
||||||
endpoint: LightWalletEndpoint = TestCoordinator.defaultEndpoint,
|
endpoint: LightWalletEndpoint = TestCoordinator.defaultEndpoint,
|
||||||
syncSessionIDGenerator: SyncSessionIDGenerator = UniqueSyncSessionIDGenerator()
|
syncSessionIDGenerator: SyncSessionIDGenerator = UniqueSyncSessionIDGenerator()
|
||||||
) async throws {
|
|
||||||
let derivationTool = DerivationTool(networkType: network.networkType)
|
|
||||||
|
|
||||||
let spendingKey = try derivationTool.deriveUnifiedSpendingKey(
|
|
||||||
seed: Environment.seedBytes,
|
|
||||||
accountIndex: 0
|
|
||||||
)
|
|
||||||
|
|
||||||
let ufvk = try derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
|
||||||
|
|
||||||
try await self.init(
|
|
||||||
alias: alias,
|
|
||||||
spendingKey: spendingKey,
|
|
||||||
unifiedFullViewingKey: ufvk,
|
|
||||||
walletBirthday: walletBirthday,
|
|
||||||
network: network,
|
|
||||||
callPrepareInConstructor: callPrepareInConstructor,
|
|
||||||
endpoint: endpoint,
|
|
||||||
syncSessionIDGenerator: syncSessionIDGenerator
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
required init(
|
|
||||||
alias: ZcashSynchronizerAlias = .default,
|
|
||||||
spendingKey: UnifiedSpendingKey,
|
|
||||||
unifiedFullViewingKey: UnifiedFullViewingKey,
|
|
||||||
walletBirthday: BlockHeight,
|
|
||||||
network: ZcashNetwork,
|
|
||||||
callPrepareInConstructor: Bool = true,
|
|
||||||
endpoint: LightWalletEndpoint = TestCoordinator.defaultEndpoint,
|
|
||||||
syncSessionIDGenerator: SyncSessionIDGenerator
|
|
||||||
) async throws {
|
) async throws {
|
||||||
await InternalSyncProgress(alias: alias, storage: UserDefaults.standard, logger: logger).rewind(to: 0)
|
await InternalSyncProgress(alias: alias, storage: UserDefaults.standard, logger: logger).rewind(to: 0)
|
||||||
|
|
||||||
self.spendingKey = spendingKey
|
let databases = TemporaryDbBuilder.build()
|
||||||
self.viewingKey = unifiedFullViewingKey
|
self.databases = databases
|
||||||
self.birthday = walletBirthday
|
|
||||||
self.databases = TemporaryDbBuilder.build()
|
|
||||||
self.network = network
|
|
||||||
|
|
||||||
let liveService = LightWalletServiceFactory(endpoint: endpoint).make()
|
|
||||||
self.service = DarksideWalletService(endpoint: endpoint, service: liveService)
|
|
||||||
|
|
||||||
let initializer = Initializer(
|
let initializer = Initializer(
|
||||||
cacheDbURL: nil,
|
cacheDbURL: nil,
|
||||||
|
@ -117,9 +80,21 @@ class TestCoordinator {
|
||||||
logLevel: .debug
|
logLevel: .debug
|
||||||
)
|
)
|
||||||
|
|
||||||
let synchronizer = SDKSynchronizer(initializer: initializer, sessionGenerator: syncSessionIDGenerator, sessionTicker: .live)
|
let derivationTool = initializer.makeDerivationTool()
|
||||||
|
|
||||||
self.synchronizer = synchronizer
|
self.spendingKey = try await derivationTool.deriveUnifiedSpendingKey(
|
||||||
|
seed: Environment.seedBytes,
|
||||||
|
accountIndex: 0
|
||||||
|
)
|
||||||
|
|
||||||
|
self.viewingKey = try await derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
|
self.birthday = walletBirthday
|
||||||
|
self.network = network
|
||||||
|
|
||||||
|
let liveService = LightWalletServiceFactory(endpoint: endpoint).make()
|
||||||
|
self.service = DarksideWalletService(endpoint: endpoint, service: liveService)
|
||||||
|
|
||||||
|
self.synchronizer = SDKSynchronizer(initializer: initializer, sessionGenerator: syncSessionIDGenerator, sessionTicker: .live)
|
||||||
subscribeToState(synchronizer: self.synchronizer)
|
subscribeToState(synchronizer: self.synchronizer)
|
||||||
|
|
||||||
if callPrepareInConstructor {
|
if callPrepareInConstructor {
|
||||||
|
|
|
@ -58,16 +58,12 @@ enum TestDbBuilder {
|
||||||
Bundle.module.url(forResource: "darkside_caches", withExtension: "db")
|
Bundle.module.url(forResource: "darkside_caches", withExtension: "db")
|
||||||
}
|
}
|
||||||
|
|
||||||
static func prepopulatedDataDbProvider() async throws -> ConnectionProvider? {
|
static func prepopulatedDataDbProvider(rustBackend: ZcashRustBackendWelding) async throws -> ConnectionProvider? {
|
||||||
guard let url = prePopulatedMainnetDataDbURL() else { return nil }
|
guard let url = prePopulatedMainnetDataDbURL() else { return nil }
|
||||||
|
|
||||||
let provider = SimpleConnectionProvider(path: url.absoluteString, readonly: true)
|
let provider = SimpleConnectionProvider(path: url.absoluteString, readonly: true)
|
||||||
|
|
||||||
let initResult = try await ZcashRustBackend.initDataDb(
|
let initResult = try await rustBackend.initDataDb(seed: Environment.seedBytes)
|
||||||
dbData: url,
|
|
||||||
seed: Environment.seedBytes,
|
|
||||||
networkType: .mainnet
|
|
||||||
)
|
|
||||||
|
|
||||||
switch initResult {
|
switch initResult {
|
||||||
case .success: return provider
|
case .success: return provider
|
||||||
|
@ -76,19 +72,19 @@ enum TestDbBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func transactionRepository() async throws -> TransactionRepository? {
|
static func transactionRepository(rustBackend: ZcashRustBackendWelding) async throws -> TransactionRepository? {
|
||||||
guard let provider = try await prepopulatedDataDbProvider() else { return nil }
|
guard let provider = try await prepopulatedDataDbProvider(rustBackend: rustBackend) else { return nil }
|
||||||
|
|
||||||
return TransactionSQLDAO(dbProvider: provider)
|
return TransactionSQLDAO(dbProvider: provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func sentNotesRepository() async throws -> SentNotesRepository? {
|
static func sentNotesRepository(rustBackend: ZcashRustBackendWelding) async throws -> SentNotesRepository? {
|
||||||
guard let provider = try await prepopulatedDataDbProvider() else { return nil }
|
guard let provider = try await prepopulatedDataDbProvider(rustBackend: rustBackend) else { return nil }
|
||||||
return SentNotesSQLDAO(dbProvider: provider)
|
return SentNotesSQLDAO(dbProvider: provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func receivedNotesRepository() async throws -> ReceivedNoteRepository? {
|
static func receivedNotesRepository(rustBackend: ZcashRustBackendWelding) async throws -> ReceivedNoteRepository? {
|
||||||
guard let provider = try await prepopulatedDataDbProvider() else { return nil }
|
guard let provider = try await prepopulatedDataDbProvider(rustBackend: rustBackend) else { return nil }
|
||||||
return ReceivedNotesSQLDAO(dbProvider: provider)
|
return ReceivedNotesSQLDAO(dbProvider: provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
import GRPC
|
import GRPC
|
||||||
import ZcashLightClientKit
|
|
||||||
import XCTest
|
import XCTest
|
||||||
import NIO
|
import NIO
|
||||||
import NIOTransportServices
|
import NIOTransportServices
|
||||||
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
enum Environment {
|
enum Environment {
|
||||||
static let lightwalletdKey = "LIGHTWALLETD_ADDRESS"
|
static let lightwalletdKey = "LIGHTWALLETD_ADDRESS"
|
||||||
|
@ -28,6 +28,11 @@ enum Environment {
|
||||||
}
|
}
|
||||||
|
|
||||||
static let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a"
|
static let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a"
|
||||||
|
|
||||||
|
static var uniqueTestTempDirectory: URL {
|
||||||
|
URL(fileURLWithPath: NSString(string: NSTemporaryDirectory())
|
||||||
|
.appendingPathComponent("tmp-\(Int.random(in: 0 ... .max))"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Constants {
|
public enum Constants {
|
||||||
|
@ -128,3 +133,21 @@ func parametersReady() -> Bool {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ZcashRustBackend {
|
||||||
|
static func makeForTests(
|
||||||
|
dbData: URL = try! __dataDbURL(),
|
||||||
|
fsBlockDbRoot: URL,
|
||||||
|
spendParamsPath: URL = SaplingParamsSourceURL.default.spendParamFileURL,
|
||||||
|
outputParamsPath: URL = SaplingParamsSourceURL.default.outputParamFileURL,
|
||||||
|
networkType: NetworkType
|
||||||
|
) -> ZcashRustBackendWelding {
|
||||||
|
ZcashRustBackend(
|
||||||
|
dbData: dbData,
|
||||||
|
fsBlockDbRoot: fsBlockDbRoot,
|
||||||
|
spendParamsPath: spendParamsPath,
|
||||||
|
outputParamsPath: outputParamsPath,
|
||||||
|
networkType: networkType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// AlternativeSynchronizerAPITestsData.swift
|
// TestsData.swift
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Created by Michal Fousek on 20.03.2023.
|
// Created by Michal Fousek on 20.03.2023.
|
||||||
|
@ -8,13 +8,29 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
class AlternativeSynchronizerAPITestsData {
|
class TestsData {
|
||||||
let derivationTools = DerivationTool(networkType: .testnet)
|
let networkType: NetworkType
|
||||||
|
|
||||||
|
lazy var initialier = {
|
||||||
|
Initializer(
|
||||||
|
cacheDbURL: nil,
|
||||||
|
fsBlockDbRoot: URL(fileURLWithPath: "/"),
|
||||||
|
dataDbURL: URL(fileURLWithPath: "/"),
|
||||||
|
pendingDbURL: URL(fileURLWithPath: "/"),
|
||||||
|
endpoint: LightWalletEndpointBuilder.default,
|
||||||
|
network: ZcashNetworkBuilder.network(for: networkType),
|
||||||
|
spendParamsURL: URL(fileURLWithPath: "/"),
|
||||||
|
outputParamsURL: URL(fileURLWithPath: "/"),
|
||||||
|
saplingParamsSourceURL: .default
|
||||||
|
)
|
||||||
|
}()
|
||||||
|
lazy var derivationTools: DerivationTool = { initialier.makeDerivationTool() }()
|
||||||
let saplingAddress = SaplingAddress(validatedEncoding: "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6")
|
let saplingAddress = SaplingAddress(validatedEncoding: "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6")
|
||||||
let unifiedAddress = UnifiedAddress(
|
let unifiedAddress = UnifiedAddress(
|
||||||
validatedEncoding: """
|
validatedEncoding: """
|
||||||
u1l9f0l4348negsncgr9pxd9d3qaxagmqv3lnexcplmufpq7muffvfaue6ksevfvd7wrz7xrvn95rc5zjtn7ugkmgh5rnxswmcj30y0pw52pn0zjvy38rn2esfgve64rj5pcmazxgpyuj
|
u1l9f0l4348negsncgr9pxd9d3qaxagmqv3lnexcplmufpq7muffvfaue6ksevfvd7wrz7xrvn95rc5zjtn7ugkmgh5rnxswmcj30y0pw52pn0zjvy38rn2esfgve64rj5pcmazxgpyuj
|
||||||
"""
|
""",
|
||||||
|
networkType: .testnet
|
||||||
)
|
)
|
||||||
let transparentAddress = TransparentAddress(validatedEncoding: "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz")
|
let transparentAddress = TransparentAddress(validatedEncoding: "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz")
|
||||||
lazy var pendingTransactionEntity = {
|
lazy var pendingTransactionEntity = {
|
||||||
|
@ -73,9 +89,19 @@ class AlternativeSynchronizerAPITestsData {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var seed: [UInt8] = Environment.seedBytes
|
var seed: [UInt8] = Environment.seedBytes
|
||||||
lazy var spendingKey: UnifiedSpendingKey = { try! derivationTools.deriveUnifiedSpendingKey(seed: seed, accountIndex: 0) }()
|
var spendingKey: UnifiedSpendingKey {
|
||||||
lazy var viewingKey: UnifiedFullViewingKey = { try! derivationTools.deriveUnifiedFullViewingKey(from: spendingKey) }()
|
get async {
|
||||||
|
try! await derivationTools.deriveUnifiedSpendingKey(seed: seed, accountIndex: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var viewingKey: UnifiedFullViewingKey {
|
||||||
|
get async {
|
||||||
|
try! await derivationTools.deriveUnifiedFullViewingKey(from: spendingKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
var birthday: BlockHeight = 123000
|
var birthday: BlockHeight = 123000
|
||||||
|
|
||||||
init() { }
|
init(networkType: NetworkType) {
|
||||||
|
self.networkType = networkType
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue