ZcashLightClientKit/ZcashLightClientKit/Synchronizer.swift

307 lines
11 KiB
Swift
Raw Normal View History

//
// Synchronizer.swift
// ZcashLightClientKit
//
// Created by Francisco Gindre on 11/5/19.
// Copyright © 2019 Electric Coin Company. All rights reserved.
//
import Foundation
/**
Represents errors thrown by a Synchronizer
*/
public enum SynchronizerError: Error {
case initFailed(message: String)
2021-05-05 12:08:57 -07:00
case notPrepared
case syncFailed
case connectionFailed(message: Error)
case generalError(message: String)
case maxRetryAttemptsReached(attempts: Int)
case connectionError(status: Int, message: String)
case networkTimeout
case uncategorized(underlyingError: Error)
case criticalError
2020-10-08 10:00:27 -07:00
case parameterMissing(underlyingError: Error)
case rewindError(underlyingError: Error)
case rewindErrorUnknownArchorHeight
2021-04-08 10:18:16 -07:00
case invalidAccount
case lightwalletdValidationFailed(underlyingError: Error)
}
2020-12-23 15:01:09 -08:00
public enum ShieldFundsError: Error {
case noUTXOFound
case insuficientTransparentFunds
case shieldingFailed(underlyingError: Error)
}
2021-02-15 11:15:50 -08:00
extension ShieldFundsError: LocalizedError {
public var errorDescription: String? {
switch self {
case .noUTXOFound:
return "Could not find UTXOs for the given t-address"
case .insuficientTransparentFunds:
return "You don't have enough confirmed transparent funds to perform a shielding transaction."
case .shieldingFailed(let underlyingError):
return "Shielding transaction failed. Reason: \(underlyingError)"
}
}
}
/**
Primary interface for interacting with the SDK. Defines the contract that specific
implementations like SdkSynchronizer fulfill.
*/
public protocol Synchronizer {
/**
Value representing the Status of this Synchronizer. As the status changes, a new
value will be emitted by KVO
*/
var status: Status { get }
/**
A flow of progress values, typically corresponding to this Synchronizer downloading blocks.
Typically, any non-zero value below 1.0 indicates that progress indicators can be shown and
a value of 1.0 signals that progress is complete and any progress indicators can be hidden. KVO Compliant
*/
var progress: Float { get }
/**
2021-05-05 12:08:57 -07:00
prepares this initializer to operate. Initializes the internal state with the given Extended Viewing Keys and a wallet birthday found in the initializer object
*/
2021-05-05 12:08:57 -07:00
func prepare() throws
/**
Starts this synchronizer within the given scope.
Implementations should leverage structured concurrency and
cancel all jobs when this scope completes.
*/
func start(retry: Bool) throws
/**
Stop this synchronizer. Implementations should ensure that calling this method cancels all
jobs that were created by this instance.
*/
func stop() throws
/**
2021-04-08 10:18:16 -07:00
Gets the sapling shielded address for the given account.
- Parameter accountIndex: the optional accountId whose address is of interest. By default, the first account is used.
- Returns the address or nil if account index is incorrect
*/
func getShieldedAddress(accountIndex: Int) -> SaplingShieldedAddress?
/**
Gets the unified address for the given account.
- Parameter accountIndex: the optional accountId whose address is of interest. By default, the first account is used.
- Returns the address or nil if account index is incorrect
*/
func getUnifiedAddress(accountIndex: Int) -> UnifiedAddress?
/**
Gets the transparent address for the given account.
- Parameter accountIndex: the optional accountId whose address is of interest. By default, the first account is used.
2021-04-08 10:18:16 -07:00
- Returns the address or nil if account index is incorrect
*/
2021-04-08 10:18:16 -07:00
func getTransparentAddress(accountIndex: Int) -> TransparentAddress?
/**
Sends zatoshi.
- Parameter spendingKey: the key that allows spends to occur.
- Parameter zatoshi: the amount of zatoshi to send.
- Parameter toAddress: the recipient's address.
- Parameter memo: the optional memo to include as part of the transaction.
- Parameter accountIndex: the optional account id to use. By default, the first account is used.
*/
func sendToAddress(spendingKey: String, zatoshi: Int64, toAddress: String, memo: String?, from accountIndex: Int, resultBlock: @escaping (_ result: Result<PendingTransactionEntity, Error>) -> Void)
2020-12-23 15:01:09 -08:00
/**
Sends zatoshi.
- Parameter spendingKey: the key that allows spends to occur.
- Parameter transparentSecretKey: the key that allows to spend transaprent funds
- Parameter memo: the optional memo to include as part of the transaction.
2021-02-15 11:15:50 -08:00
- Parameter accountIndex: the optional account id that will be used to shield your funds to. By default, the first account is used.
2020-12-23 15:01:09 -08:00
*/
func shieldFunds(spendingKey: String, transparentSecretKey: String, memo: String?, from accountIndex: Int, resultBlock: @escaping (_ result: Result<PendingTransactionEntity, Error>) -> Void)
/**
Attempts to cancel a transaction that is about to be sent. Typically, cancellation is only
an option if the transaction has not yet been submitted to the server.
- Parameter transaction: the transaction to cancel.
- Returns: true when the cancellation request was successful. False when it is too late.
*/
func cancelSpend(transaction: PendingTransactionEntity) -> Bool
/**
all outbound pending transactions that have been sent but are awaiting confirmations
*/
var pendingTransactions: [PendingTransactionEntity] { get }
/**
al the transactions that are on the blockchain
*/
var clearedTransactions: [ConfirmedTransactionEntity] { get }
/**
All transactions that are related to sending funds
*/
var sentTransactions: [ConfirmedTransactionEntity] { get }
/**
all transactions related to receiving funds
*/
var receivedTransactions: [ConfirmedTransactionEntity] { get }
/**
a repository serving transactions in a paginated manner
- Parameter kind: Transaction Kind expected from this PaginatedTransactionRepository
*/
func paginatedTransactions(of kind: TransactionKind) -> PaginatedTransactionRepository
/**
Returns a list of confirmed transactions that preceed the given transaction with a limit count.
- Parameters:
- from: the confirmed transaction from which the query should start from or nil to retrieve from the most recent transaction
- limit: the maximum amount of items this should return if available
- Returns: an array with the given Transactions or nil
*/
func allConfirmedTransactions(from transaction: ConfirmedTransactionEntity?, limit: Int) throws -> [ConfirmedTransactionEntity]?
2020-10-06 16:35:17 -07:00
/**
gets the latest downloaded height from the compact block cache
*/
func latestDownloadedHeight() throws -> BlockHeight
/**
Gets the latest block height from the provided Lightwallet endpoint
*/
func latestHeight(result: @escaping (Result<BlockHeight, Error>) -> Void)
/**
Gets the latest block height from the provided Lightwallet endpoint
Blocking
*/
func latestHeight() throws -> BlockHeight
2020-12-11 12:15:29 -08:00
2021-02-17 15:02:25 -08:00
/**
Gets the latests UTXOs for the given address from the specified height on
*/
func refreshUTXOs(address: String, from height: BlockHeight, result: @escaping (Result<RefreshedUTXOs,Error>) -> Void)
2021-02-17 15:02:25 -08:00
/**
gets the last stored unshielded balance
*/
2021-04-08 10:18:16 -07:00
func getTransparentBalance(accountIndex: Int) throws -> WalletBalance
2021-02-17 15:02:25 -08:00
/**
gets the shielded total balance (includes verified and unverified balance)
*/
func getShieldedBalance(accountIndex: Int) -> Int64
/**
gets the shielded verified balance (anchor is 10 blocks back)
*/
func getShieldedVerifiedBalance(accountIndex: Int) -> Int64
/**
Stops the synchronizer and rescans the known blocks with the current keys.
- Parameter policy: the rewind policy
- Throws rewindErrorUnknownArchorHeight when the rewind points to an invalid height
- Throws rewindError for other errors
- Note rewind does not trigger notifications as a reorg would. You need to restart the synchronizer afterwards
*/
func rewind(_ policy: RewindPolicy) throws
}
/**
The Status of the synchronizer
*/
public enum Status {
2021-06-07 16:00:33 -07:00
2021-05-05 12:08:57 -07:00
/**
2021-06-07 16:00:33 -07:00
Indicates that this Synchronizer is actively preparing to start, which usually involves
setting up database tables, migrations or taking other maintenance steps that need to
occur after an upgrade.
2021-05-05 12:08:57 -07:00
*/
case unprepared
/**
Indicates that [stop] has been called on this Synchronizer and it will no longer be used.
*/
case stopped
/**
Indicates that this Synchronizer is disconnected from its lightwalletd server.
When set, a UI element may want to turn red.
*/
case disconnected
/**
2021-06-07 16:00:33 -07:00
Indicates that this Synchronizer is actively downloading new blocks from the server.
*/
case downloading
/**
Indicates that this Synchronizer is actively validating new blocks that were downloaded
from the server. Blocks need to be verified before they are scanned. This confirms that
each block is chain-sequential, thereby detecting missing blocks and reorgs.
*/
2021-06-07 16:00:33 -07:00
case validating
/**
Indicates that this Synchronizer is actively scanning new valid blocks that were downloaded
from the server.
*/
case scanning
/**
Indicates that this Synchronizer is actively enhancing newly scanned blocks with
additional transaction details, fetched from the server.
*/
case enhancing
/**
fetches the transparent balance and stores it locally
*/
case fetching
/**
Indicates that this Synchronizer is fully up to date and ready for all wallet functions.
When set, a UI element may want to turn green.
*/
case synced
2021-06-07 16:00:33 -07:00
public var isSyncing: Bool {
switch self {
case .disconnected, .synced, .synced, .unprepared:
return false
default:
return true
}
}
}
/**
Kind of transactions handled by a Synchronizer
*/
public enum TransactionKind {
case sent
case received
case all
}
/**
Type of rewind available
birthday: rewinds the local state to this wallet's birthday
2021-04-19 10:07:50 -07:00
height: rewinds to the nearest blockheight to the one given as argument.
transaction: rewinds to the nearest height based on the anchor of the provided transaction.
*/
public enum RewindPolicy {
case birthday
case height(blockheight: BlockHeight)
case transaction(_ transaction: TransactionEntity)
case quick
}