Commit Graph

21 Commits

Author SHA1 Message Date
Michal Fousek 5d2b2298b5 [#1012] Introduce dependency injection in the SDK
Closes #1012

- This is the first change for the dependency injection. This change
  adds `DIContainer` which is used to register and resolve dependencies.
- Then this change shows how `DIContainer` can be used to resolve
  dependencies. And it also shows how to mock dependencies in tests.
- Constructors of `Initializer` are changed to support mocking of
  depedendencies. But it doesn't affect public API in any way.
- Depedencies are registered in `Dependencies.setup()`. Then in the code
  `container.resolve(SomeType.self)` is called to get instance of the
  dependency.
- `ZcashTestCase` class is added. It inherits from `XCTestCase` and
  should be used for base class in tests. `ZcashTestCase` takes care of
  creation of `DIContainer` for dependencies mocking. In future we can
  maybe move there more things that are used in each test.
- Lot is missing here. Not all the code is using dependency injection.
  Tests for `DIContainer` are missing. Only `OfflineTests` work now
  (other tests can't be even compiled). It will be added in future
  changes.
2023-05-08 14:58:49 +02:00
Michal Fousek 0032fedde7 [#442] Introduce parallel downloading and scanning
- `BlockDownloaderImpl` is changed. It now spawns detached Task to
  download blocks. So blocks can be downloaded in parallel with scanning
  process.
- `Synchronizer.stop()` is no longer async.
- Blocks cache cleaning is changed. It's not possible to drop the whole
  cache now. There are some blocks pre-downloaded which weren't scanned
  yet.
2023-05-05 09:35:43 +02:00
Matthew Watt 58b99c8fb1
[#1013] - Enable more granular control over logging behavior (#1014)
* Add new model for logging configuration

* Fix the example app and update the changelog
2023-05-02 16:59:49 -03:00
Michal Fousek 724d410fad
[#361] Introduce ZcashError (#1005)
This PR introduces `ZcashError` enum. This enum represents any error
that can be thrown inside of the SDK and outside of the SDK. Also
`ZcashError` is used in `LightWalletGRPCService` and handled in
`CompactBlockProcessor` as example.

Why enum? First I tried this with some structure which contained code,
message and underlyingError. Problem was when some specific place in the
SDK would like to attach some additional data to error. I didn't want to
add some generic dictionary to store anything with the error.

So I used enum to identify error. Each member can have specified amount
of associated values. So specific error can bring some context data. And
it's type safe.

Each error has also a code. Relationship between errors and codes is
1:1. It may looks bit redundant but it's important. The client app now
can choose how to process errors. Either identify those by the error
itself or by code.

Definition or errors and codes is in `ZcashErrorDefinition`. And then
`ZcashError` and `ZcashErrorCode` are generated by Sourcery. Thanks to
this it is easier to maintain the final code. And it gives us ability to
generate any kind of documentation for the errors and codes. I created
simple example of this in this PR. And it doesn't make the SDK
completely dependent on the Sourcery. Final structures aren't super
complicated and can be written manually if needed.

[#923] Update error handling in DatabaseStorageManager.swift

- cleanup of DatabaseStorageManager, not used anymore
- ZcashError for SimpleConnectionProvider

Revert "[#923] Update error handling in DatabaseStorageManager.swift"

This reverts commit 94e028d31a.

Fix script which generates ZcashError

[#922] Update error handling in DatabaseMigrationManager.swift

Closes #922

[#923] Update error handling in DatabaseStorageManager.swift

- The DatabaseStorageManager is not used so I deleted it
- SimpleConnectionProvider's errors updated

Fix tests

[#955] Update error handling in SaplingParameterDownloader

Closes #955

[#936] Update error handling in NotesDao

Closes #936

[#935] Update error handling in BlockDao

Closes #935

[#931] InternalSyncProgress.computeNextState doesn't need to throw

Closes #931

[#950] Update error handling in rust backend

Closes #949
Closes #950

[#941] Update error handling in AccountEntity

Closes #941

[#928] Update error handling in FSCompactBlockRepository

Closes #928

[#925] Update error handling in BlockDownloaderService (#974)

- BlockDownloaderService errors updated

[#924] Update error handling in BlockDownloader (#973)

- BlockDownloaderStream nextBlock updated

[#942] Update error handling in TransactionEntity (#977)

- ZcashTransaction init errors converted to the ZcashError

[#939] Update error handling in TransactionDao (#976)

- TransactionRepositoryError removed and replaced with ZcashError
- all TransactionDAO errors converted to ZcashError

[#943] Update error handling in ZcashCompactBlock

Closes #943

[#945] Update error handling in Memo

Closes #945

[#934] Update error handling in Checkpoint

Closes #944
Closes #934

[#938] Update error handling in PendingTransactionDao

Closes #938

[#926] Update error handling in BlockEnhancer

- WIP, switching to transaction repository to unblock this ticket

[#926] Update error handling in BlockEnhancer

- enhancer's errors done

[#926] Update error handling in BlockEnhancer (#994)

- cleanup

[#952] Update error handling in DerivationTool

Closes #952

[#932] Update error handling in BlockValidator

Closes #932

[#940] Update error handling in UnspentTransactionOutputDao

Closes #940

[#946] Update error handling in WalletTypes

Closes #946

[#954] Update error handling in WalletTransactionEncoder

Closes #954

[#953] Update error handling in PersistentTransactionManager

Closes #953

[#956] Update error handling in Initializer

Closes #956

[#947] Update error handling in Zatoshi (#996)

- Zatoshi's errors converted to ZcashError

[#927] Update error handling in UTXOFetcher (#997)

- UTXOFetcher resolved

Use let instead of var where applicable

In the SDK `var` was used on places where `let` would be sufficient. And
default strategy in Swift should use use `let` until mutability is
required. So all these places are changed. No logic is changed.

[#933] Update error handling in CompactBlockProcessor

- CompactBlockProcessor's errors refactored to ZcashError

[#933] Update error handling in CompactBlockProcessor #999

- comments addressed

[#951] Update error handling in SDKSynchronizer

- SDKSynchronizer's errors refactored to ZcashError

[#951] Update error handling in SDKSynchronizer (#1002)

- comments resolved

Make DerivationTool constructor public

DerivationTool.init should be public. This was removed by accident when
adopting async.

[#361] Add changelog
2023-04-24 18:15:20 -03:00
Lukas Korba 99b24c2081
[#908] Add last and latest blocks data to Synchronizer State (#911)
- attached to the processor's timer
- added latest scanned time and latest block height
- sample app showing the new values alongside with the %
- unit tests fixed
- latestBlock() API added
- the transaction repository is no longer used to update the exposed values during the syncing
2023-04-14 09:08:37 +02:00
Michal Fousek 2bbc5800bd [#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-04-11 17:51:28 +02:00
Francisco Gindre 6b7fbdd908
[#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 09:02:05 -03:00
Michal Fousek 5c979f42e6 [#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-27 20:42:52 +02:00
Michal Fousek 436fa1fc47 [#831] Add SDKSynchronizer wrappers for non-async API
This change introduces two new protocols: `ClosureSynchronizer` and
`CombineSynchronizer`. These two protocols define API that doesn't use
`async`. So the client can choose exactly which API it wants to use.
    This change also introduces two new objects: `ClosureSDKSynchronizer`
and `CombineSDKSynchronizer`. These two implement the respective protocols
mentioned above. Both are structures. Neither of these two keeps any state.
Thanks to this each is very cheap to create. And usage of these two isn't
mutually exclusive. So devs can really choose the best SDK API for each
part of the client app.

[#831] Use async inside of the SDKSynchronizer

- In general lot of methods inside the `SDKSynchronizer` and
  `CompactBlockProcessoer` which weren't async are now async. And other
  changes are made because of this change.
- `CompactBlockProcessor` no longer uses Combine to communicate with
  `SDKSynchronizer`. Reason for this is that Combine doesn't play great
  with async. Closure passed to `sink` isn't async.
- Because of this and because of how our tests work (receiving signals
  from CBP directly) `CompactBlockProcessor` must be able to handle more
  event closures. Not just one. So it now has `eventClosures`
  dictionary. It's little bit strange but it works fine.
- `SyncStatus` inside the `SDKSynchronizer` was previously protected by
  lock. Now it's protected by simple actor wrapper.
- Changes in tests are minimal. Changes were mady only because
  `CompactBlockProcessor` changes from Combine to closures.

[#831] Add tests for ClosureSDKSynchronizer

- Added tests are testing in general if the `ClosuresSDKSynchronizer` is correctly
  calling `Synchronizer` and if the values are correctly returned.
- `ClosuresSDKSynchronizer` doesn't contain any logic but it is public
  API and we should be sure that it works correctly.

[#831] Add tests for CombineSDKSynchronizer

[#831] Add changelog
2023-03-21 22:47:19 +01:00
Lukas Korba 587977d1d1
[#818] Swift 5.7 syntax update (#828)
- code updated
2023-03-14 09:11:17 -03:00
Michal Fousek ea4d56536e Set oslog inside OSLogger public for read
- This is necessary to finish https://github.com/zcash/secant-ios-wallet/issues/529.
  The Secant has special log method for logging tca stuff. And this
  method will be in extension of `OSLogger` and it needs to access
  `oslog`.
2023-03-01 14:07:14 +01:00
Michal Fousek d09b00cabe [#795] Include sapling-spend file into bundle for tests
Closes #795

- Added structure `SaplingParamsSourceURL` which holds source URLs for
  sapling-spend file and sapling-output file. URLs are ultimately passed
  to `SaplingParameterDownloader`.
- This is done so it's possible to pass different URLs when running
  tests.
- sapling-spend file and sapling-output file are in tests bundle. And
  when running tests these files are loaded from bundle and not from
  network.
2023-02-20 10:03:16 +01:00
Lukas Korba f69da50ba9
[#747] Remove SampleLogger and replace it with OSLogger (#748)
- SampleLogger removed
- OSLogger used
- category default
2023-01-26 18:14:07 +01:00
Francisco Gindre 851023842f
[#612] Remove Support for Cocoapods (#706)
Our main dependency, Swift-GRPC is dropping support for Cocoapods from version 1.8.2.

Even though they make a great work at maintaining backwards compatibility, we will eventually be forced to drop Cocoapods support.

We've reached out partners like NighthawkApps, Horizontal Systems (Unstoppable) and Edge, who have reported not depending on Cocoapods.

We intend to end Cocoapods support on 0.18.0.

Closes #612
2023-01-06 12:26:00 -03:00
Lukas Korba 6029a75038
[#637] Make sapling parameter download part of processing blocks (#650)
- sync process enhanced to try to download sapling params if needed
- tests fixed
- failing import Crypto -> import CryptoKit
- download params only if there are sapling funds
2022-11-29 07:38:28 +01:00
Lukas Korba cc99fbad30
[#590] Fix or delete CompactBlockProcessorTests disabled tests it not needed (#653)
- The tests were fine in the end but Stream needed to be finished in any way, caused "for await" syntax to never finish
2022-11-28 15:08:55 +01:00
Lukas Korba d36c1fbc14
[#631] Verify SHA1 correctness of Sapling files after downloading (#643)
- Verification of the SHA1 after downloading the file(s)
- Private API is encapsulated in private extension
2022-11-23 09:47:56 +01:00
Lukas Korba 61683a85f3 [486] sendToAddress async/await
- sendToAddress and SaplingParameterDownloader refactored to async
- unit tests WIP

[486] sendToAddress async/await

- testing code cleanup

[#486] sendToAddress async/await

- reducing number of Tasks in Sample app

[#486] sendToAddress async/await

- I finally figure out how to make the dark side tests async, using new sendToAddress APIs and pass, POC done, 18 more tests to refactor

[#486] sendToAddress async/await

- async sendToAddress unit test refactored except NetworkUpgradeTests

[#486] sendToAddress async/await

- NetworkUpgradeTests refactored to async API

[#486] sendToAddress async/await

- cleanup

[#486] sendToAddress async/await (#536)

- PR comments resolved
2022-09-21 13:47:17 +02:00
Francisco Gindre b9ae012e09
[#381] Move Zatoshi and Amount Types to the SDK (#396)
Closes #381

This commit brings a Zatoshi type developed on the Secant project,
helper classes like Clamped and tests.

Zatoshi has been incorporated as a Codable type for SQLite Swift
to allow serialization into the pending database.

FIXES on Demo App

fix comments
2022-06-22 16:45:37 -03:00
dh-ecc 80e6ec200b
[#326] Load Checkpoint files from bundle.
Closes #326 

Implements loading checkpoints from the bundle the same way the android SDK does. 


* Add checkpoint files

* Add checkpoint files as resources to package

* Remove stencil files

* Update wallet birthday methods to use bundled checkpoints

* [clean up] Fix test build failure

* Add Cocoapods support

* Fix for behaviour across SPM and Cocoapods

* Add test for checkpoint retrieval

* Use latest GRPC v1.x

* update checkpoint files to match android sdk
2022-05-05 18:30:17 -03:00
Daniel Haight 86d1257ab5 Remove dependecy on rust sources 2022-02-28 17:03:20 +00:00