create + prepare API

This commit is contained in:
Francisco Gindre 2021-05-05 16:08:57 -03:00
parent 5aa8afd2aa
commit 39837009a4
3 changed files with 49 additions and 89 deletions

View File

@ -66,6 +66,7 @@ public class Initializer {
private(set) var transactionRepository: TransactionRepository
private(set) var accountRepository: AccountRepository
private(set) var downloader: CompactBlockDownloader
private(set) public var viewingKeys: [UnifiedViewingKey]
private(set) public var walletBirthday: WalletBirthday
/**
Constructs the Initializer
@ -83,6 +84,7 @@ public class Initializer {
endpoint: LightWalletEndpoint,
spendParamsURL: URL,
outputParamsURL: URL,
viewingKeys: [UnifiedViewingKey],
walletBirthday: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT,
alias: String = "",
loggerProxy: Logger? = nil) {
@ -104,6 +106,7 @@ public class Initializer {
downloader: CompactBlockDownloader(service: lwdService, storage: storage),
spendParamsURL: spendParamsURL,
outputParamsURL: outputParamsURL,
viewingKeys: viewingKeys,
walletBirthday: walletBirthday,
alias: alias,
loggerProxy: loggerProxy
@ -125,6 +128,7 @@ public class Initializer {
downloader: CompactBlockDownloader,
spendParamsURL: URL,
outputParamsURL: URL,
viewingKeys: [UnifiedViewingKey],
walletBirthday: BlockHeight,
alias: String = "",
loggerProxy: Logger? = nil
@ -144,69 +148,13 @@ public class Initializer {
self.transactionRepository = repository
self.accountRepository = accountRepository
self.downloader = downloader
self.viewingKeys = viewingKeys
self.walletBirthday = WalletBirthday.birthday(with: walletBirthday)
}
/**
Initialize the wallet with the given seed and return the related private keys for each
account specified or null if the wallet was previously initialized and block data exists on
disk. When this method returns null, that signals that the wallet will need to retrieve the
private keys from its own secure storage. In other words, the private keys are only given out
once for each set of database files. Subsequent calls to [initialize] will only load the Rust
library and return null.
'compactBlockCache.db' and 'transactionData.db' files are created by this function (if they
do not already exist). These files can be given a prefix for scenarios where multiple wallets
operate in one app--for instance, when sweeping funds from another wallet seed.
- Parameters:
- seedProvider: the seed to use for initializing this wallet.
- walletBirthdayHeight: the height corresponding to when the wallet seed was created. If null, this signals that the wallet is being born.
- numberOfAccounts: the number of accounts to create from this seed.
*/
public func initialize(seedBytes: [UInt8], numberOfAccounts: Int = 1) throws -> [String]? {
do {
try rustBackend.initDataDb(dbData: dataDbURL)
} catch RustWeldingError.dataDbNotEmpty {
// this is fine
} catch {
throw InitializerError.dataDbInitFailed
}
do {
try rustBackend.initBlocksTable(dbData: dataDbURL, height: Int32(walletBirthday.height), hash: walletBirthday.hash, time: walletBirthday.time, saplingTree: walletBirthday.tree)
} catch RustWeldingError.dataDbNotEmpty {
// this is fine
} catch {
throw InitializerError.dataDbInitFailed
}
let lastDownloaded = (try? downloader.storage.latestHeight()) ?? self.walletBirthday.height
// resume from last downloaded block
lowerBoundHeight = max(walletBirthday.height, lastDownloaded)
var accounts: [String]? = nil
do {
guard let a = rustBackend.initAccountsTable(dbData: dataDbURL, seed: seedBytes, accounts: Int32(numberOfAccounts)) else {
throw rustBackend.lastError() ?? InitializerError.accountInitFailed
}
accounts = a
} catch RustWeldingError.dataDbNotEmpty {
// this is fine
} catch {
throw InitializerError.dataDbInitFailed
}
let migrationManager = MigrationManager(cacheDbConnection: SimpleConnectionProvider(path: cacheDbURL.path),
dataDbConnection: SimpleConnectionProvider(path: dataDbURL.path), pendingDbConnection: SimpleConnectionProvider(path: pendingDbURL.path))
try migrationManager.performMigration(seedBytes: seedBytes)
return accounts
}
/**
__TEMPORARILY UNAVAILABLE__
Initialize the wallet with the given seed and return the related private keys for each
account specified or null if the wallet was previously initialized and block data exists on
disk. When this method returns null, that signals that the wallet will need to retrieve the
@ -221,7 +169,7 @@ public class Initializer {
- viewingKeys: Extended Full Viewing Keys to initialize the DBs with
*/
public func initialize(unifiedViewingKeys: [UnifiedViewingKey], walletBirthday: BlockHeight) throws {
public func initialize() throws {
do {
try rustBackend.initDataDb(dbData: dataDbURL)
@ -230,23 +178,21 @@ public class Initializer {
} catch {
throw InitializerError.dataDbInitFailed
}
let birthday = WalletBirthday.birthday(with: walletBirthday)
self.walletBirthday = birthday
do {
try rustBackend.initBlocksTable(dbData: dataDbURL, height: Int32(birthday.height), hash: birthday.hash, time: birthday.time, saplingTree: birthday.tree)
try rustBackend.initBlocksTable(dbData: dataDbURL, height: Int32(walletBirthday.height), hash: walletBirthday.hash, time: walletBirthday.time, saplingTree: walletBirthday.tree)
} catch RustWeldingError.dataDbNotEmpty {
// this is fine
} catch {
throw InitializerError.dataDbInitFailed
}
let lastDownloaded = (try? downloader.storage.latestHeight()) ?? birthday.height
let lastDownloaded = (try? downloader.storage.latestHeight()) ?? walletBirthday.height
// resume from last downloaded block
lowerBoundHeight = max(birthday.height, lastDownloaded)
lowerBoundHeight = max(walletBirthday.height, lastDownloaded)
do {
guard try rustBackend.initAccountsTable(dbData: dataDbURL, uvks: unifiedViewingKeys) else {
guard try rustBackend.initAccountsTable(dbData: dataDbURL, uvks: viewingKeys) else {
throw rustBackend.lastError() ?? InitializerError.accountInitFailed
}
} catch RustWeldingError.dataDbNotEmpty {
@ -258,7 +204,7 @@ public class Initializer {
let migrationManager = MigrationManager(cacheDbConnection: SimpleConnectionProvider(path: cacheDbURL.path),
dataDbConnection: SimpleConnectionProvider(path: dataDbURL.path), pendingDbConnection: SimpleConnectionProvider(path: pendingDbURL.path))
try migrationManager.performMigration(uvks: unifiedViewingKeys)
try migrationManager.performMigration(uvks: viewingKeys)
}
/**

View File

@ -13,6 +13,7 @@ Represents errors thrown by a Synchronizer
*/
public enum SynchronizerError: Error {
case initFailed(message: String)
case notPrepared
case syncFailed
case connectionFailed(message: Error)
case generalError(message: String)
@ -68,14 +69,9 @@ public protocol Synchronizer {
var progress: Float { get }
/**
Initialize the internal state with the given Extended Viewing Keys and a wallet birthday
- Parameter viewingKeys: an array containing the viewing keys to initialize the internal state
- Parameter walletBirthday: the eldest when the different keys differ in birthday
- Throws: Initializer Errors and RustWeldingError if fails
- Note: The subsequent initializations don't have any effect or failure
prepares this initializer to operate. Initializes the internal state with the given Extended Viewing Keys and a wallet birthday found in the initializer object
*/
func initialize(unifiedViewingKeys: [UnifiedViewingKey], walletBirthday: BlockHeight) throws
func prepare() throws
/**
Starts this synchronizer within the given scope.
@ -222,6 +218,10 @@ public protocol Synchronizer {
The Status of the synchronizer
*/
public enum Status {
/**
This synchronizer is not ready to start
*/
case unprepared
/**
Indicates that [stop] has been called on this Synchronizer and it will no longer be used.
*/

View File

@ -98,7 +98,7 @@ public class SDKSynchronizer: Synchronizer {
*/
public convenience init(initializer: Initializer) throws {
try self.init(status: .disconnected,
try self.init(status: .unprepared,
initializer: initializer,
transactionManager: try OutboundTransactionManagerBuilder.build(initializer: initializer),
transactionRepository: initializer.transactionRepository,
@ -128,26 +128,36 @@ public class SDKSynchronizer: Synchronizer {
self.blockProcessor.stop()
}
public func initialize(unifiedViewingKeys: [UnifiedViewingKey], walletBirthday: BlockHeight) throws {
try self.initializer.initialize(unifiedViewingKeys: unifiedViewingKeys, walletBirthday: walletBirthday)
try self.blockProcessor.setStartHeight(WalletBirthday.birthday(with: walletBirthday).height)
public func initialize() throws {
try self.initializer.initialize()
try self.blockProcessor.setStartHeight(initializer.walletBirthday.height)
}
public func prepare() throws {
try self.initializer.initialize()
try self.blockProcessor.setStartHeight(initializer.walletBirthday.height)
self.status = .disconnected
}
/**
Starts the synchronizer
- Throws: CompactBlockProcessorError when failures occur
*/
public func start(retry: Bool = false) throws {
guard status == .stopped || status == .disconnected || status == .synced else {
assert(true,"warning: synchronizer started when already started") // TODO: remove this assertion sometime in the near future
return
}
do {
try blockProcessor.start(retry: retry)
} catch {
throw mapError(error)
switch status {
case .unprepared:
throw SynchronizerError.notPrepared
case .syncing:
assert(true,"warning: synchronizer started when already started") // TODO: remove this assertion sometime in the near future
LoggerProxy.debug("warning: synchronizer started when already started")
return
default:
do {
try blockProcessor.start(retry: retry)
} catch {
throw mapError(error)
}
}
}
@ -156,7 +166,10 @@ public class SDKSynchronizer: Synchronizer {
*/
public func stop() {
guard status != .stopped, status != .disconnected else { return }
guard status != .stopped, status != .disconnected else {
LoggerProxy.info("attempted to stop when status was: \(status)")
return
}
blockProcessor.stop(cancelTasks: true)
}
@ -562,7 +575,8 @@ public class SDKSynchronizer: Synchronizer {
NotificationCenter.default.post(name: Notification.Name.synchronizerSynced, object: self)
case .syncing:
NotificationCenter.default.post(name: Notification.Name.synchronizerSyncing, object: self)
case .unprepared:
break
}
}
// MARK: book keeping