ZcashLightClientKit/Tests/OfflineTests/SynchronizerOfflineTests.swift

406 lines
15 KiB
Swift
Raw Normal View History

[#209] Add support for multiple instances of the SDKSynchronizer Closes #209. [#845] Introduce ZcashSynchronizerAlias enum Closes #845. [#852] SDKSynchronizer using queues label based on the alias Closes #852. [#847] Remove posibility to use DatabaseStorageManager as singleton Closes #847. [#850] Remove synchronizerConnectionStateChanged notification Closes #850. [#855] Add check if the Alias is already used Closes #855 - Added `UsedAliasesChecker` utility which is used to register aliases that are in use. - `prepare()` and `wipe()` methods now check if the current alias can't be used and if not then `InitializerError.aliasAlreadyInUse` is thrown/emitted. - Some public methods that could cause harm if used with the Alias that is already in use now throw `SynchronizerError.notPrepared`. Thanks to this the client app is forced to call `prepare()` first. And `prepare()` does check for the Alias. - Added tests for new conditions. [#849] Make InternalSyncProgress aware of the Alias Closes #849. [#853] Only instance with default Alias migrates legacy cache DB Closes #853. [#851] Apply the Alias to the URLs Closes #851. - `Initializer` now updates paths according to alias before paths are used anywhere in the SDK. - Paths update can fail. It would be incovenient for the client apps to handle errors thrown from `Initiliazer` constructor. So the error is then handled in `SDKSynchronizer.prepare()` or `SDKSynchronizer.wipe()`. [#846] Stop using SDKMetrics as singleton (#862) - metrics are not longer a singleton - tests fixed - metrics outside init of the synchronizer [#848] Make logger aware of the alias - logger is now an instance passed throughout the sdk instead of a static proxy [#848] Make logger aware of the alias (#868) - comments addressed [#848] Make logger aware of the alias (#868) - returning protocol back Fix typos [#856] Add possibility to test multiple synchronizers in the sample app Closes #856. - Added `alias` property to `Synchronizer`. - Added `SyncBlocksListViewController` which provides UI to use multiple synchronizers at once. [#209] Add changelog - Add changelog for #209. - Overall improve readability of the rendered changelog. Tickets references are now prefixed with `###` instead of `- `. Fix compilation
2023-03-22 05:47:32 -07:00
//
// SynchronizerOfflineTests.swift
//
//
// Created by Michal Fousek on 23.03.2023.
//
import Combine
import Foundation
@testable import TestUtils
import XCTest
@testable import ZcashLightClientKit
class SynchronizerOfflineTests: XCTestCase {
[#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.
2023-03-31 10:10:35 -07:00
let data = TestsData(networkType: .testnet)
[#209] Add support for multiple instances of the SDKSynchronizer Closes #209. [#845] Introduce ZcashSynchronizerAlias enum Closes #845. [#852] SDKSynchronizer using queues label based on the alias Closes #852. [#847] Remove posibility to use DatabaseStorageManager as singleton Closes #847. [#850] Remove synchronizerConnectionStateChanged notification Closes #850. [#855] Add check if the Alias is already used Closes #855 - Added `UsedAliasesChecker` utility which is used to register aliases that are in use. - `prepare()` and `wipe()` methods now check if the current alias can't be used and if not then `InitializerError.aliasAlreadyInUse` is thrown/emitted. - Some public methods that could cause harm if used with the Alias that is already in use now throw `SynchronizerError.notPrepared`. Thanks to this the client app is forced to call `prepare()` first. And `prepare()` does check for the Alias. - Added tests for new conditions. [#849] Make InternalSyncProgress aware of the Alias Closes #849. [#853] Only instance with default Alias migrates legacy cache DB Closes #853. [#851] Apply the Alias to the URLs Closes #851. - `Initializer` now updates paths according to alias before paths are used anywhere in the SDK. - Paths update can fail. It would be incovenient for the client apps to handle errors thrown from `Initiliazer` constructor. So the error is then handled in `SDKSynchronizer.prepare()` or `SDKSynchronizer.wipe()`. [#846] Stop using SDKMetrics as singleton (#862) - metrics are not longer a singleton - tests fixed - metrics outside init of the synchronizer [#848] Make logger aware of the alias - logger is now an instance passed throughout the sdk instead of a static proxy [#848] Make logger aware of the alias (#868) - comments addressed [#848] Make logger aware of the alias (#868) - returning protocol back Fix typos [#856] Add possibility to test multiple synchronizers in the sample app Closes #856. - Added `alias` property to `Synchronizer`. - Added `SyncBlocksListViewController` which provides UI to use multiple synchronizers at once. [#209] Add changelog - Add changelog for #209. - Overall improve readability of the rendered changelog. Tickets references are now prefixed with `###` instead of `- `. Fix compilation
2023-03-22 05:47:32 -07:00
var network: ZcashNetwork!
var cancellables: [AnyCancellable] = []
override func setUp() async throws {
try await super.setUp()
network = ZcashNetworkBuilder.network(for: .testnet)
cancellables = []
}
override func tearDown() async throws {
try await super.tearDown()
network = nil
cancellables = []
}
func testCallPrepareWithAlreadyUsedAliasThrowsError() async throws {
let firstTestCoordinator = try await TestCoordinator(
alias: .custom("alias"),
walletBirthday: 10,
network: network,
callPrepareInConstructor: false
)
let secondTestCoordinator = try await TestCoordinator(
alias: .custom("alias"),
walletBirthday: 10,
network: network,
callPrepareInConstructor: false
)
do {
_ = try await firstTestCoordinator.prepare(seed: Environment.seedBytes)
} catch {
XCTFail("Unpected fail. Prepare should succeed. \(error)")
}
do {
_ = try await secondTestCoordinator.prepare(seed: Environment.seedBytes)
XCTFail("Prepare should fail.")
} catch { }
}
func testWhenSynchronizerIsDeallocatedAliasIsntUsedAnymore() async throws {
var testCoordinator: TestCoordinator! = try await TestCoordinator(
alias: .default,
walletBirthday: 10,
network: network,
callPrepareInConstructor: false
)
do {
_ = try await testCoordinator.prepare(seed: Environment.seedBytes)
} catch {
XCTFail("Unpected fail. Prepare should succeed. \(error)")
}
testCoordinator = try await TestCoordinator(
alias: .default,
walletBirthday: 10,
network: network,
callPrepareInConstructor: false
)
do {
_ = try await testCoordinator.prepare(seed: Environment.seedBytes)
} catch {
XCTFail("Unpected fail. Prepare should succeed. \(error)")
}
}
func testCallWipeWithAlreadyUsedAliasThrowsError() async throws {
let firstTestCoordinator = try await TestCoordinator(alias: .default, walletBirthday: 10, network: network, callPrepareInConstructor: false)
let secondTestCoordinator = try await TestCoordinator(alias: .default, walletBirthday: 10, network: network, callPrepareInConstructor: false)
let firstWipeExpectation = XCTestExpectation(description: "First wipe expectation")
firstTestCoordinator.synchronizer.wipe()
.sink(
receiveCompletion: { result in
switch result {
case .finished:
firstWipeExpectation.fulfill()
case let .failure(error):
XCTFail("Unexpected error when calling wipe \(error)")
}
},
receiveValue: { _ in }
)
.store(in: &cancellables)
wait(for: [firstWipeExpectation], timeout: 1)
let secondWipeExpectation = XCTestExpectation(description: "Second wipe expectation")
secondTestCoordinator.synchronizer.wipe()
.sink(
receiveCompletion: { result in
switch result {
case .finished:
XCTFail("Second wipe should fail with error.")
case let .failure(error):
if let error = error as? InitializerError, case .aliasAlreadyInUse = error {
secondWipeExpectation.fulfill()
} else {
XCTFail("Wipe failed with unexpected error: \(error)")
}
}
},
receiveValue: { _ in }
)
.store(in: &cancellables)
wait(for: [secondWipeExpectation], timeout: 1)
}
func testPrepareCanBeCalledAfterWipeWithSameInstanceOfSDKSynchronizer() async throws {
let testCoordinator = try await TestCoordinator(alias: .default, walletBirthday: 10, network: network, callPrepareInConstructor: false)
let expectation = XCTestExpectation(description: "Wipe expectation")
testCoordinator.synchronizer.wipe()
.sink(
receiveCompletion: { result in
switch result {
case .finished:
expectation.fulfill()
case let .failure(error):
XCTFail("Unexpected error when calling wipe \(error)")
}
},
receiveValue: { _ in }
)
.store(in: &cancellables)
wait(for: [expectation], timeout: 1)
do {
_ = try await testCoordinator.prepare(seed: Environment.seedBytes)
} catch {
XCTFail("Prepare after wipe should succeed.")
}
}
func testSendToAddressCalledWithoutPrepareThrowsError() async throws {
let testCoordinator = try await TestCoordinator(alias: .default, walletBirthday: 10, network: network, callPrepareInConstructor: false)
do {
_ = try await testCoordinator.synchronizer.sendToAddress(
spendingKey: testCoordinator.spendingKey,
zatoshi: Zatoshi(1),
toAddress: .transparent(data.transparentAddress),
memo: nil
)
XCTFail("Send to address should fail.")
} catch {
if let error = error as? SynchronizerError, case .notPrepared = error {
} else {
XCTFail("Send to address failed with unexpected error: \(error)")
}
}
}
func testShieldFundsCalledWithoutPrepareThrowsError() async throws {
let testCoordinator = try await TestCoordinator(alias: .default, walletBirthday: 10, network: network, callPrepareInConstructor: false)
do {
_ = try await testCoordinator.synchronizer.shieldFunds(
spendingKey: testCoordinator.spendingKey,
memo: Memo(string: "memo"),
shieldingThreshold: Zatoshi(1)
)
XCTFail("Shield funds should fail.")
} catch {
if let error = error as? SynchronizerError, case .notPrepared = error {
} else {
XCTFail("Shield funds failed with unexpected error: \(error)")
}
}
}
func testRefreshUTXOCalledWithoutPrepareThrowsError() async throws {
let testCoordinator = try await TestCoordinator(alias: .default, walletBirthday: 10, network: network, callPrepareInConstructor: false)
do {
_ = try await testCoordinator.synchronizer.refreshUTXOs(address: data.transparentAddress, from: 1)
XCTFail("Shield funds should fail.")
} catch {
if let error = error as? SynchronizerError, case .notPrepared = error {
} else {
XCTFail("Shield funds failed with unexpected error: \(error)")
}
}
}
func testRewindCalledWithoutPrepareThrowsError() async throws {
let testCoordinator = try await TestCoordinator(alias: .default, walletBirthday: 10, network: network, callPrepareInConstructor: false)
let expectation = XCTestExpectation()
testCoordinator.synchronizer.rewind(.quick)
.sink(
receiveCompletion: { result in
switch result {
case .finished:
XCTFail("Rewind should fail with error.")
case let .failure(error):
if let error = error as? SynchronizerError, case .notPrepared = error {
expectation.fulfill()
} else {
XCTFail("Rewind failed with unexpected error: \(error)")
}
}
},
receiveValue: { _ in }
)
.store(in: &cancellables)
wait(for: [expectation], timeout: 1)
}
func testURLsParsingFailsInInitialierPrepareThenThrowsError() async throws {
let validFileURL = URL(fileURLWithPath: "/some/valid/path/to.file")
let validDirectoryURL = URL(fileURLWithPath: "/some/valid/path/to/directory")
let invalidPathURL = URL(string: "https://whatever")!
let initializer = Initializer(
cacheDbURL: nil,
fsBlockDbRoot: validDirectoryURL,
dataDbURL: validFileURL,
pendingDbURL: invalidPathURL,
endpoint: LightWalletEndpointBuilder.default,
network: ZcashNetworkBuilder.network(for: .testnet),
spendParamsURL: validFileURL,
outputParamsURL: validFileURL,
saplingParamsSourceURL: .default,
alias: .default,
logLevel: .debug
)
XCTAssertNotNil(initializer.urlsParsingError)
let synchronizer = SDKSynchronizer(initializer: initializer)
do {
[#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.
2023-03-31 10:10:35 -07:00
let derivationTool = initializer.makeDerivationTool()
let spendingKey = try await derivationTool.deriveUnifiedSpendingKey(
[#209] Add support for multiple instances of the SDKSynchronizer Closes #209. [#845] Introduce ZcashSynchronizerAlias enum Closes #845. [#852] SDKSynchronizer using queues label based on the alias Closes #852. [#847] Remove posibility to use DatabaseStorageManager as singleton Closes #847. [#850] Remove synchronizerConnectionStateChanged notification Closes #850. [#855] Add check if the Alias is already used Closes #855 - Added `UsedAliasesChecker` utility which is used to register aliases that are in use. - `prepare()` and `wipe()` methods now check if the current alias can't be used and if not then `InitializerError.aliasAlreadyInUse` is thrown/emitted. - Some public methods that could cause harm if used with the Alias that is already in use now throw `SynchronizerError.notPrepared`. Thanks to this the client app is forced to call `prepare()` first. And `prepare()` does check for the Alias. - Added tests for new conditions. [#849] Make InternalSyncProgress aware of the Alias Closes #849. [#853] Only instance with default Alias migrates legacy cache DB Closes #853. [#851] Apply the Alias to the URLs Closes #851. - `Initializer` now updates paths according to alias before paths are used anywhere in the SDK. - Paths update can fail. It would be incovenient for the client apps to handle errors thrown from `Initiliazer` constructor. So the error is then handled in `SDKSynchronizer.prepare()` or `SDKSynchronizer.wipe()`. [#846] Stop using SDKMetrics as singleton (#862) - metrics are not longer a singleton - tests fixed - metrics outside init of the synchronizer [#848] Make logger aware of the alias - logger is now an instance passed throughout the sdk instead of a static proxy [#848] Make logger aware of the alias (#868) - comments addressed [#848] Make logger aware of the alias (#868) - returning protocol back Fix typos [#856] Add possibility to test multiple synchronizers in the sample app Closes #856. - Added `alias` property to `Synchronizer`. - Added `SyncBlocksListViewController` which provides UI to use multiple synchronizers at once. [#209] Add changelog - Add changelog for #209. - Overall improve readability of the rendered changelog. Tickets references are now prefixed with `###` instead of `- `. Fix compilation
2023-03-22 05:47:32 -07:00
seed: Environment.seedBytes,
accountIndex: 0
)
[#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.
2023-03-31 10:10:35 -07:00
let viewingKey = try await derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
[#209] Add support for multiple instances of the SDKSynchronizer Closes #209. [#845] Introduce ZcashSynchronizerAlias enum Closes #845. [#852] SDKSynchronizer using queues label based on the alias Closes #852. [#847] Remove posibility to use DatabaseStorageManager as singleton Closes #847. [#850] Remove synchronizerConnectionStateChanged notification Closes #850. [#855] Add check if the Alias is already used Closes #855 - Added `UsedAliasesChecker` utility which is used to register aliases that are in use. - `prepare()` and `wipe()` methods now check if the current alias can't be used and if not then `InitializerError.aliasAlreadyInUse` is thrown/emitted. - Some public methods that could cause harm if used with the Alias that is already in use now throw `SynchronizerError.notPrepared`. Thanks to this the client app is forced to call `prepare()` first. And `prepare()` does check for the Alias. - Added tests for new conditions. [#849] Make InternalSyncProgress aware of the Alias Closes #849. [#853] Only instance with default Alias migrates legacy cache DB Closes #853. [#851] Apply the Alias to the URLs Closes #851. - `Initializer` now updates paths according to alias before paths are used anywhere in the SDK. - Paths update can fail. It would be incovenient for the client apps to handle errors thrown from `Initiliazer` constructor. So the error is then handled in `SDKSynchronizer.prepare()` or `SDKSynchronizer.wipe()`. [#846] Stop using SDKMetrics as singleton (#862) - metrics are not longer a singleton - tests fixed - metrics outside init of the synchronizer [#848] Make logger aware of the alias - logger is now an instance passed throughout the sdk instead of a static proxy [#848] Make logger aware of the alias (#868) - comments addressed [#848] Make logger aware of the alias (#868) - returning protocol back Fix typos [#856] Add possibility to test multiple synchronizers in the sample app Closes #856. - Added `alias` property to `Synchronizer`. - Added `SyncBlocksListViewController` which provides UI to use multiple synchronizers at once. [#209] Add changelog - Add changelog for #209. - Overall improve readability of the rendered changelog. Tickets references are now prefixed with `###` instead of `- `. Fix compilation
2023-03-22 05:47:32 -07:00
_ = try await synchronizer.prepare(with: Environment.seedBytes, viewingKeys: [viewingKey], walletBirthday: 123000)
XCTFail("Failure of prepare is expected.")
} catch {
if let error = error as? InitializerError, case let .cantUpdateURLWithAlias(failedURL) = error {
XCTAssertEqual(failedURL, invalidPathURL)
} else {
XCTFail("Failed with unexpected error: \(error)")
}
}
}
func testURLsParsingFailsInInitialierWipeThenThrowsError() async throws {
let validFileURL = URL(fileURLWithPath: "/some/valid/path/to.file")
let validDirectoryURL = URL(fileURLWithPath: "/some/valid/path/to/directory")
let invalidPathURL = URL(string: "https://whatever")!
let initializer = Initializer(
cacheDbURL: nil,
fsBlockDbRoot: validDirectoryURL,
dataDbURL: validFileURL,
pendingDbURL: invalidPathURL,
endpoint: LightWalletEndpointBuilder.default,
network: ZcashNetworkBuilder.network(for: .testnet),
spendParamsURL: validFileURL,
outputParamsURL: validFileURL,
saplingParamsSourceURL: .default,
alias: .default,
logLevel: .debug
)
XCTAssertNotNil(initializer.urlsParsingError)
let synchronizer = SDKSynchronizer(initializer: initializer)
let expectation = XCTestExpectation()
synchronizer.wipe()
.sink(
receiveCompletion: { result in
switch result {
case .finished:
XCTFail("Failure of wipe is expected.")
case let .failure(error):
if let error = error as? InitializerError, case let .cantUpdateURLWithAlias(failedURL) = error {
XCTAssertEqual(failedURL, invalidPathURL)
expectation.fulfill()
} else {
XCTFail("Failed with unexpected error: \(error)")
}
}
},
receiveValue: { _ in }
)
.store(in: &cancellables)
wait(for: [expectation], timeout: 1)
}
[#895] Add Sync Session ID Synchronizer State (#906) Closes #895 Add Sync Session ID to `SynchronizerState`. A SyncSession is an attempt to sync the blockchain within the lifetime of a Synchronizer. A Synchronizer can sync many times, when synced it will refresh every ~20 seconds +- random padding. each sync attempt will have a different UUID even if it's from the same instance of SDKSynchronizer. **How are SyncSessions are delimited? With `SyncStatus` changes.** changes from [`.unprepared`|`.error`|`.disconnected`|`.stopped`] to `.syncing` assign a new sessionID to the synchronizer. Any other transitions won't. `areTwoStatusesDifferent ` was refactored to a helper function of `SyncStatus` **How are IDs generated?** ID generation is not mandated but delegated to a protocol `SyncSessionIDGenerator`. Tests inject their own deterministic generator to avoid test flakiness. Default implementation of SyncSessionIDGenerator is ````Swift struct UniqueSyncSessionIDGenerator {} extension UniqueSyncSessionIDGenerator: SyncSessionIDGenerator { func nextID() -> UUID { UUID() } } ```` **SyncSession Pseudo-Atomicity and thread safety** SyncSession is a type alias of a GenericActor holding a UUID ```` typealias SyncSession = GenericActor<UUID> extension SyncSession { /// updates the current sync session to a new value with the given generator /// - Parameters generator: a `SyncSessionIDGenerator` /// - returns: the `UUID` of the newly updated value. @discardableResult func newSession(with generator: SyncSessionIDGenerator) async -> UUID { return await self.update(generator.nextID()) } } ```` Closes #895 SessionTicker struct to control session transitions. switching to `.unprepared` now makes syncID to be `.nullID`
2023-04-07 05:02:05 -07:00
func testIsNewSessionOnUnpreparedToValidTransition() {
XCTAssertTrue(SessionTicker.live.isNewSyncSession(.unprepared, .syncing(.nullProgress)))
}
func testIsNotNewSessionOnUnpreparedToStateThatWontSync() {
XCTAssertFalse(SessionTicker.live.isNewSyncSession(.unprepared, .error(SynchronizerError.criticalError)))
XCTAssertFalse(SessionTicker.live.isNewSyncSession(.unprepared, .disconnected))
XCTAssertFalse(SessionTicker.live.isNewSyncSession(.unprepared, .unprepared))
}
func testIsNotNewSessionOnUnpreparedToInvalidOrUnexpectedTransitions() {
XCTAssertFalse(SessionTicker.live.isNewSyncSession(.unprepared, .synced))
XCTAssertFalse(SessionTicker.live.isNewSyncSession(.unprepared, .fetching))
XCTAssertFalse(SessionTicker.live.isNewSyncSession(.unprepared, .enhancing(.zero)))
}
func testIsNotNewSyncSessionOnSameSession() {
XCTAssertFalse(
SessionTicker.live.isNewSyncSession(
.syncing(
BlockProgress(startHeight: 1, targetHeight: 10, progressHeight: 3)
),
.syncing(
BlockProgress(startHeight: 1, targetHeight: 10, progressHeight: 4)
)
)
)
}
func testIsNewSyncSessionWhenRestartingFromError() {
XCTAssertTrue(
SessionTicker.live.isNewSyncSession(
.error(SynchronizerError.generalError(message: "some error")),
.syncing(
BlockProgress(startHeight: 1, targetHeight: 10, progressHeight: 4)
)
)
)
}
func testIsNewSyncSessionWhenStartingFromSynced() {
XCTAssertTrue(
SessionTicker.live.isNewSyncSession(
.synced,
.syncing(
BlockProgress(startHeight: 1, targetHeight: 10, progressHeight: 4)
)
)
)
}
func testIsNewSyncSessionWhenStartingFromDisconnected() {
XCTAssertTrue(
SessionTicker.live.isNewSyncSession(
.disconnected,
.syncing(
BlockProgress(startHeight: 1, targetHeight: 10, progressHeight: 4)
)
)
)
}
func testIsNewSyncSessionWhenStartingFromStopped() {
XCTAssertTrue(
SessionTicker.live.isNewSyncSession(
.stopped,
.syncing(
BlockProgress(startHeight: 1, targetHeight: 10, progressHeight: 4)
)
)
)
}
func testSyncStatusesDontDifferWhenOuterStatusIsTheSame() {
XCTAssertFalse(SyncStatus.error(SynchronizerError.criticalError).isDifferent(from: .error(.invalidAccount)))
XCTAssertFalse(SyncStatus.disconnected.isDifferent(from: .disconnected))
XCTAssertFalse(SyncStatus.fetching.isDifferent(from: .fetching))
XCTAssertFalse(SyncStatus.stopped.isDifferent(from: .stopped))
XCTAssertFalse(SyncStatus.synced.isDifferent(from: .synced))
XCTAssertFalse(SyncStatus.syncing(.nullProgress).isDifferent(from: .syncing(.nullProgress)))
XCTAssertFalse(SyncStatus.unprepared.isDifferent(from: .unprepared))
}
[#209] Add support for multiple instances of the SDKSynchronizer Closes #209. [#845] Introduce ZcashSynchronizerAlias enum Closes #845. [#852] SDKSynchronizer using queues label based on the alias Closes #852. [#847] Remove posibility to use DatabaseStorageManager as singleton Closes #847. [#850] Remove synchronizerConnectionStateChanged notification Closes #850. [#855] Add check if the Alias is already used Closes #855 - Added `UsedAliasesChecker` utility which is used to register aliases that are in use. - `prepare()` and `wipe()` methods now check if the current alias can't be used and if not then `InitializerError.aliasAlreadyInUse` is thrown/emitted. - Some public methods that could cause harm if used with the Alias that is already in use now throw `SynchronizerError.notPrepared`. Thanks to this the client app is forced to call `prepare()` first. And `prepare()` does check for the Alias. - Added tests for new conditions. [#849] Make InternalSyncProgress aware of the Alias Closes #849. [#853] Only instance with default Alias migrates legacy cache DB Closes #853. [#851] Apply the Alias to the URLs Closes #851. - `Initializer` now updates paths according to alias before paths are used anywhere in the SDK. - Paths update can fail. It would be incovenient for the client apps to handle errors thrown from `Initiliazer` constructor. So the error is then handled in `SDKSynchronizer.prepare()` or `SDKSynchronizer.wipe()`. [#846] Stop using SDKMetrics as singleton (#862) - metrics are not longer a singleton - tests fixed - metrics outside init of the synchronizer [#848] Make logger aware of the alias - logger is now an instance passed throughout the sdk instead of a static proxy [#848] Make logger aware of the alias (#868) - comments addressed [#848] Make logger aware of the alias (#868) - returning protocol back Fix typos [#856] Add possibility to test multiple synchronizers in the sample app Closes #856. - Added `alias` property to `Synchronizer`. - Added `SyncBlocksListViewController` which provides UI to use multiple synchronizers at once. [#209] Add changelog - Add changelog for #209. - Overall improve readability of the rendered changelog. Tickets references are now prefixed with `###` instead of `- `. Fix compilation
2023-03-22 05:47:32 -07:00
}