Merge pull request #1241 from LukasKorba/1236-Use-of-recoverUntil

[#1236] Use of recoverUntil
This commit is contained in:
Lukas Korba 2023-09-08 17:41:36 +02:00 committed by GitHub
commit 0d56e4fcc6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 76 additions and 43 deletions

View File

@ -12,6 +12,12 @@ be able to write to this location after it creates this directory. It is suggest
a subdirectory of the `Documents` directory. If this information is stored in `Documents` then the
system itself won't remove these data.
### Changed
Synchronizer's prepare(...) public API changed, `viewingKeys: [UnifiedFullViewingKey]` has been removed and `for walletMode: WalletInitMode` added.
`WalletInitMode` is an enum with 3 cases: .newWallet, .restoreWallet and .existingWallet. Use `.newWallet` when preparing the SDKSynchronizer for a brand new wallet
that has been generated. Use `.restoreWallet` when wallet is about to be restored from a seed and `.existingWallet` for all other scenarios.
### Removed
### [#1181] Correct computation of progress for Spend before Sync

View File

@ -45,7 +45,8 @@ class SendViewController: UIViewController {
closureSynchronizer.prepare(
with: DemoAppConfig.defaultSeed,
walletBirthday: DemoAppConfig.defaultBirthdayHeight
walletBirthday: DemoAppConfig.defaultBirthdayHeight,
for: .existingWallet
) { result in
loggerProxy.debug("Prepare result: \(result)")
}

View File

@ -69,7 +69,8 @@ class SyncBlocksListViewController: UIViewController {
if syncStatus == .unprepared {
_ = try! await synchronizer.prepare(
with: synchronizerData.seed,
walletBirthday: synchronizerData.birthday
walletBirthday: synchronizerData.birthday,
for: .existingWallet
)
}

View File

@ -150,7 +150,8 @@ class SyncBlocksViewController: UIViewController {
do {
_ = try await synchronizer.prepare(
with: DemoAppConfig.defaultSeed,
walletBirthday: DemoAppConfig.defaultBirthdayHeight
walletBirthday: DemoAppConfig.defaultBirthdayHeight,
for: .existingWallet
)
} catch {
loggerProxy.error(error.toZcashError().message)

View File

@ -25,6 +25,7 @@ public protocol ClosureSynchronizer {
func prepare(
with seed: [UInt8]?,
walletBirthday: BlockHeight,
for walletMode: WalletInitMode,
completion: @escaping (Result<Initializer.InitializationResult, Error>) -> Void
)

View File

@ -24,7 +24,8 @@ public protocol CombineSynchronizer {
func prepare(
with seed: [UInt8]?,
walletBirthday: BlockHeight
walletBirthday: BlockHeight,
for walletMode: WalletInitMode
) -> SinglePublisher<Initializer.InitializationResult, Error>
func start(retry: Bool) -> CompletablePublisher<Error>

View File

@ -409,7 +409,7 @@ public class Initializer {
/// - Parameter seed: ZIP-32 Seed bytes for the wallet that will be initialized
/// - Throws: `InitializerError.dataDbInitFailed` if the creation of the dataDb fails
/// `InitializerError.accountInitFailed` if the account table can't be initialized.
func initialize(with seed: [UInt8]?, walletBirthday: BlockHeight) async throws -> InitializationResult {
func initialize(with seed: [UInt8]?, walletBirthday: BlockHeight, for walletMode: WalletInitMode) async throws -> InitializationResult {
try await storage.create()
if case .seedRequired = try await rustBackend.initDataDb(seed: seed) {
@ -422,11 +422,16 @@ public class Initializer {
// If there are no accounts it must be created, the default amount of accounts is 1
if let seed, try accountRepository.getAll().isEmpty {
// TODO: [#1236] set the recoverUntil properly, https://github.com/zcash/ZcashLightClientKit/issues/1236
var chainTip: UInt32?
if walletMode == .restoreWallet {
chainTip = UInt32(try await lightWalletService.latestBlockHeight())
}
_ = try await rustBackend.createAccount(
seed: seed,
treeState: try checkpoint.treeState().serializedData(partial: false).bytes,
recoverUntil: nil
recoverUntil: chainTip
)
}

View File

@ -122,6 +122,7 @@ public protocol Synchronizer: AnyObject {
/// - Parameters:
/// - seed: ZIP-32 Seed bytes for the wallet that will be initialized
/// - walletBirthday: Birthday of wallet.
/// - walletMode: Set `.newWallet` when preparing synchronizer for a brand new generated wallet, `.restoreWallet` when wallet is about to be restored from a seed and `.existingWallet` for all other scenarios.
/// - Throws:
/// - `aliasAlreadyInUse` if the Alias used to create this instance is already used by other instance.
/// - `cantUpdateURLWithAlias` if the updating of paths in `Initilizer` according to alias fails. When this happens it means that
@ -130,7 +131,8 @@ public protocol Synchronizer: AnyObject {
/// - Some other `ZcashError` thrown by lower layer of the SDK.
func prepare(
with seed: [UInt8]?,
walletBirthday: BlockHeight
walletBirthday: BlockHeight,
for walletMode: WalletInitMode
) async throws -> Initializer.InitializationResult
/// Starts this synchronizer within the given scope.
@ -407,6 +409,16 @@ enum InternalSyncStatus: Equatable {
}
}
/// Mode of the Synchronizer's initialization for the wallet.
public enum WalletInitMode: Equatable {
/// For brand new wallet - typically when users creates a new wallet.
case newWallet
/// For a wallet that is about to be restored. Typically when a user wants to restore a wallet from a seed.
case restoreWallet
/// All other cases - typically when clients just start the process e.g. every regular app start for mobile apps.
case existingWallet
}
/// Kind of transactions handled by a Synchronizer
public enum TransactionKind {
case sent

View File

@ -34,10 +34,11 @@ extension ClosureSDKSynchronizer: ClosureSynchronizer {
public func prepare(
with seed: [UInt8]?,
walletBirthday: BlockHeight,
for walletMode: WalletInitMode,
completion: @escaping (Result<Initializer.InitializationResult, Error>) -> Void
) {
AsyncToClosureGateway.executeThrowingAction(completion) {
return try await self.synchronizer.prepare(with: seed, walletBirthday: walletBirthday)
return try await self.synchronizer.prepare(with: seed, walletBirthday: walletBirthday, for: walletMode)
}
}

View File

@ -33,10 +33,11 @@ extension CombineSDKSynchronizer: CombineSynchronizer {
public func prepare(
with seed: [UInt8]?,
walletBirthday: BlockHeight
walletBirthday: BlockHeight,
for walletMode: WalletInitMode
) -> SinglePublisher<Initializer.InitializationResult, Error> {
AsyncToCombineGateway.executeThrowingAction() {
return try await self.synchronizer.prepare(with: seed, walletBirthday: walletBirthday)
return try await self.synchronizer.prepare(with: seed, walletBirthday: walletBirthday, for: walletMode)
}
}

View File

@ -127,7 +127,8 @@ public class SDKSynchronizer: Synchronizer {
public func prepare(
with seed: [UInt8]?,
walletBirthday: BlockHeight
walletBirthday: BlockHeight,
for walletMode: WalletInitMode
) async throws -> Initializer.InitializationResult {
guard await status == .unprepared else { return .success }
@ -137,7 +138,7 @@ public class SDKSynchronizer: Synchronizer {
try await utxoRepository.initialise()
if case .seedRequired = try await self.initializer.initialize(with: seed, walletBirthday: walletBirthday) {
if case .seedRequired = try await self.initializer.initialize(with: seed, walletBirthday: walletBirthday, for: walletMode) {
return .seedRequired
}

View File

@ -101,7 +101,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
}
func testPrepareSucceed() throws {
synchronizerMock.prepareWithWalletBirthdayClosure = { receivedSeed, receivedWalletBirthday in
synchronizerMock.prepareWithWalletBirthdayForClosure = { receivedSeed, receivedWalletBirthday, _ in
XCTAssertEqual(receivedSeed, self.data.seed)
XCTAssertEqual(receivedWalletBirthday, self.data.birthday)
return .success
@ -109,7 +109,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
let expectation = XCTestExpectation()
synchronizer.prepare(with: data.seed, walletBirthday: data.birthday) { result in
synchronizer.prepare(with: data.seed, walletBirthday: data.birthday, for: .newWallet) { result in
switch result {
case let .success(status):
XCTAssertEqual(status, .success)
@ -123,13 +123,13 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
}
func testPrepareThrowsError() throws {
synchronizerMock.prepareWithWalletBirthdayClosure = { _, _ in
synchronizerMock.prepareWithWalletBirthdayForClosure = { _, _, _ in
throw "Some error"
}
let expectation = XCTestExpectation()
synchronizer.prepare(with: data.seed, walletBirthday: data.birthday) { result in
synchronizer.prepare(with: data.seed, walletBirthday: data.birthday, for: .newWallet) { result in
switch result {
case .success:
XCTFail("Error should be thrown.")

View File

@ -101,8 +101,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
}
func testPrepareSucceed() throws {
let mockedViewingKey = self.data.viewingKey
synchronizerMock.prepareWithWalletBirthdayClosure = { receivedSeed, receivedWalletBirthday in
synchronizerMock.prepareWithWalletBirthdayForClosure = { receivedSeed, receivedWalletBirthday, _ in
XCTAssertEqual(receivedSeed, self.data.seed)
XCTAssertEqual(receivedWalletBirthday, self.data.birthday)
return .success
@ -110,7 +109,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
let expectation = XCTestExpectation()
synchronizer.prepare(with: data.seed, walletBirthday: data.birthday)
synchronizer.prepare(with: data.seed, walletBirthday: data.birthday, for: .newWallet)
.sink(
receiveCompletion: { result in
switch result {
@ -130,14 +129,13 @@ class CombineSynchronizerOfflineTests: XCTestCase {
}
func testPrepareThrowsError() throws {
let mockedViewingKey = self.data.viewingKey
synchronizerMock.prepareWithWalletBirthdayClosure = { _, _ in
synchronizerMock.prepareWithWalletBirthdayForClosure = { _, _, _ in
throw "Some error"
}
let expectation = XCTestExpectation()
synchronizer.prepare(with: data.seed, walletBirthday: data.birthday)
synchronizer.prepare(with: data.seed, walletBirthday: data.birthday, for: .newWallet)
.sink(
receiveCompletion: { result in
switch result {

View File

@ -304,7 +304,7 @@ class SynchronizerOfflineTests: ZcashTestCase {
let synchronizer = SDKSynchronizer(initializer: initializer)
do {
_ = try await synchronizer.prepare(with: Environment.seedBytes, walletBirthday: 123000)
_ = try await synchronizer.prepare(with: Environment.seedBytes, walletBirthday: 123000, for: .newWallet)
XCTFail("Failure of prepare is expected.")
} catch {
if let error = error as? ZcashError, case let .initializerCantUpdateURLWithAlias(failedURL) = error {

View File

@ -32,11 +32,15 @@ class WalletTests: ZcashTestCase {
}
func testWalletInitialization() async throws {
let derivationTool = TestsData(networkType: network.networkType).derivationTools
let spendingKey = try derivationTool.deriveUnifiedSpendingKey(seed: seedData.bytes, accountIndex: 0)
let viewingKey = try derivationTool.deriveUnifiedFullViewingKey(from: spendingKey)
let mockContainer = DIContainer()
mockContainer.isTestEnvironment = true
let serviceMock = LightWalletServiceMock()
mockContainer.mock(type: LightWalletService.self, isSingleton: true) { _ in serviceMock }
serviceMock.latestBlockHeightReturnValue = 1
let wallet = Initializer(
container: mockContainer,
cacheDbURL: nil,
fsBlockDbRoot: testTempDirectory,
generalStorageURL: testGeneralStorageDirectory,
@ -50,7 +54,7 @@ class WalletTests: ZcashTestCase {
let synchronizer = SDKSynchronizer(initializer: wallet)
do {
guard case .success = try await synchronizer.prepare(with: seedData.bytes, walletBirthday: 663194) else {
guard case .success = try await synchronizer.prepare(with: seedData.bytes, walletBirthday: 663194, for: .newWallet) else {
XCTFail("Failed to initDataDb. Expected `.success` got: `.seedRequired`")
return
}

View File

@ -1185,25 +1185,25 @@ class SynchronizerMock: Synchronizer {
// MARK: - prepare
var prepareWithWalletBirthdayThrowableError: Error?
var prepareWithWalletBirthdayCallsCount = 0
var prepareWithWalletBirthdayCalled: Bool {
return prepareWithWalletBirthdayCallsCount > 0
var prepareWithWalletBirthdayForThrowableError: Error?
var prepareWithWalletBirthdayForCallsCount = 0
var prepareWithWalletBirthdayForCalled: Bool {
return prepareWithWalletBirthdayForCallsCount > 0
}
var prepareWithWalletBirthdayReceivedArguments: (seed: [UInt8]?, walletBirthday: BlockHeight)?
var prepareWithWalletBirthdayReturnValue: Initializer.InitializationResult!
var prepareWithWalletBirthdayClosure: (([UInt8]?, BlockHeight) async throws -> Initializer.InitializationResult)?
var prepareWithWalletBirthdayForReceivedArguments: (seed: [UInt8]?, walletBirthday: BlockHeight, walletMode: WalletInitMode)?
var prepareWithWalletBirthdayForReturnValue: Initializer.InitializationResult!
var prepareWithWalletBirthdayForClosure: (([UInt8]?, BlockHeight, WalletInitMode) async throws -> Initializer.InitializationResult)?
func prepare(with seed: [UInt8]?, walletBirthday: BlockHeight) async throws -> Initializer.InitializationResult {
if let error = prepareWithWalletBirthdayThrowableError {
func prepare(with seed: [UInt8]?, walletBirthday: BlockHeight, for walletMode: WalletInitMode) async throws -> Initializer.InitializationResult {
if let error = prepareWithWalletBirthdayForThrowableError {
throw error
}
prepareWithWalletBirthdayCallsCount += 1
prepareWithWalletBirthdayReceivedArguments = (seed: seed, walletBirthday: walletBirthday)
if let closure = prepareWithWalletBirthdayClosure {
return try await closure(seed, walletBirthday)
prepareWithWalletBirthdayForCallsCount += 1
prepareWithWalletBirthdayForReceivedArguments = (seed: seed, walletBirthday: walletBirthday, walletMode: walletMode)
if let closure = prepareWithWalletBirthdayForClosure {
return try await closure(seed, walletBirthday, walletMode)
} else {
return prepareWithWalletBirthdayReturnValue
return prepareWithWalletBirthdayForReturnValue
}
}

View File

@ -110,7 +110,7 @@ class TestCoordinator {
}
func prepare(seed: [UInt8]) async throws -> Initializer.InitializationResult {
return try await synchronizer.prepare(with: seed, walletBirthday: self.birthday)
return try await synchronizer.prepare(with: seed, walletBirthday: self.birthday, for: .newWallet)
}
func stop() async throws {