Clear SwiftLint on ZcashLightClientKit

This commit is contained in:
Francisco Gindre 2021-09-15 09:21:29 -03:00
parent 185cbb4b91
commit b1a0b01673
56 changed files with 1096 additions and 774 deletions

View File

@ -5,6 +5,7 @@
// Created by Francisco Gindre on 06/09/2019.
// Copyright © 2019 Electric Coin Company. All rights reserved.
//
// swiftlint:disable all
import UIKit
import ZcashLightClientKit
@ -33,14 +34,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
if let wallet = wallet {
return wallet
} else {
let unifiedViewingKeys = try! DerivationTool(networkType: ZCASH_NETWORK.networkType).deriveUnifiedViewingKeysFromSeed(DemoAppConfig.seed, numberOfAccounts: 1)
let wallet = Initializer(cacheDbURL:try! __cacheDbURL(),
dataDbURL: try! __dataDbURL(),
pendingDbURL: try! __pendingDbURL(),
let unifiedViewingKeys = try! DerivationTool(networkType: kZcashNetwork.networkType).deriveUnifiedViewingKeysFromSeed(DemoAppConfig.seed, numberOfAccounts: 1)
let wallet = Initializer(cacheDbURL:try! cacheDbURLHelper(),
dataDbURL: try! dataDbURLHelper(),
pendingDbURL: try! pendingDbURLHelper(),
endpoint: DemoAppConfig.endpoint,
network: ZCASH_NETWORK,
spendParamsURL: try! __spendParamsURL(),
outputParamsURL: try! __outputParamsURL(),
network: kZcashNetwork,
spendParamsURL: try! spendParamsURLHelper(),
outputParamsURL: try! outputParamsURLHelper(),
viewingKeys: unifiedViewingKeys,
walletBirthday: DemoAppConfig.birthdayHeight,
loggerProxy: loggerProxy)
@ -49,7 +50,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
try! wallet.initialize()
var storage = SampleStorage.shared
storage!.seed = Data(DemoAppConfig.seed)
storage!.privateKey = try! DerivationTool(networkType: ZCASH_NETWORK.networkType).deriveSpendingKeys(seed: DemoAppConfig.seed, numberOfAccounts: 1)[0]
storage!.privateKey = try! DerivationTool(networkType: kZcashNetwork.networkType).deriveSpendingKeys(seed: DemoAppConfig.seed, numberOfAccounts: 1)[0]
self.wallet = wallet
return wallet
}
@ -65,7 +66,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
return
}
NotificationBubble.display(in: window!.rootViewController!.view, options: NotificationBubble.sucessOptions(animation: NotificationBubble.Animation.fade(duration: 1)), attributedText: NSAttributedString(string: "Transaction \(String(describing: tx.id))mined!")) {}
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
@ -112,19 +112,19 @@ extension AppDelegate {
func clearDatabases() {
do {
try FileManager.default.removeItem(at: try __cacheDbURL())
try FileManager.default.removeItem(at: try cacheDbURLHelper())
} catch {
loggerProxy.error("error clearing cache DB: \(error)")
}
do {
try FileManager.default.removeItem(at: try __dataDbURL())
try FileManager.default.removeItem(at: try dataDbURLHelper())
} catch {
loggerProxy.error("error clearing data db: \(error)")
}
do {
try FileManager.default.removeItem(at: try __pendingDbURL())
try FileManager.default.removeItem(at: try pendingDbURLHelper())
} catch {
loggerProxy.error("error clearing data db: \(error)")
}
@ -148,38 +148,38 @@ extension Synchronizer {
}
}
func __documentsDirectory() throws -> URL {
func documentsDirectoryHelper() throws -> URL {
try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
}
func __cacheDbURL() throws -> URL {
try __documentsDirectory().appendingPathComponent(ZCASH_NETWORK.constants.DEFAULT_DB_NAME_PREFIX+ZcashSDK.DEFAULT_CACHES_DB_NAME, isDirectory: false)
func cacheDbURLHelper() throws -> URL {
try documentsDirectoryHelper().appendingPathComponent(kZcashNetwork.constants.defaultDbNamePrefix+ZcashSDK.defaultCacheDbName, isDirectory: false)
}
func __dataDbURL() throws -> URL {
try __documentsDirectory().appendingPathComponent(ZCASH_NETWORK.constants.DEFAULT_DB_NAME_PREFIX+ZcashSDK.DEFAULT_DATA_DB_NAME, isDirectory: false)
func dataDbURLHelper() throws -> URL {
try documentsDirectoryHelper().appendingPathComponent(kZcashNetwork.constants.defaultDbNamePrefix+ZcashSDK.defaultDataDbName, isDirectory: false)
}
func __pendingDbURL() throws -> URL {
try __documentsDirectory().appendingPathComponent(ZCASH_NETWORK.constants.DEFAULT_DB_NAME_PREFIX+ZcashSDK.DEFAULT_PENDING_DB_NAME)
func pendingDbURLHelper() throws -> URL {
try documentsDirectoryHelper().appendingPathComponent(kZcashNetwork.constants.defaultDbNamePrefix+ZcashSDK.defaultPendingDbName)
}
func __spendParamsURL() throws -> URL {
try __documentsDirectory().appendingPathComponent("sapling-spend.params")
func spendParamsURLHelper() throws -> URL {
try documentsDirectoryHelper().appendingPathComponent("sapling-spend.params")
}
func __outputParamsURL() throws -> URL {
try __documentsDirectory().appendingPathComponent("sapling-output.params")
func outputParamsURLHelper() throws -> URL {
try documentsDirectoryHelper().appendingPathComponent("sapling-output.params")
}
public extension NotificationBubble {
static func sucessOptions(animation: NotificationBubble.Animation) -> [NotificationBubble.Style] {
return [ NotificationBubble.Style.animation(animation),
return [
NotificationBubble.Style.animation(animation),
NotificationBubble.Style.margins(UIEdgeInsets(top: 40, left: 0, bottom: 0, right: 0)),
NotificationBubble.Style.cornerRadius(8),
NotificationBubble.Style.duration(timeInterval: 10),
NotificationBubble.Style.backgroundColor(UIColor.green)]
NotificationBubble.Style.backgroundColor(UIColor.green)
]
}
}

View File

@ -9,4 +9,4 @@
import Foundation
import ZcashLightClientKit
let ZCASH_NETWORK = ZcashNetworkBuilder.network(for: .mainnet)
let kZcashNetwork = ZcashNetworkBuilder.network(for: .mainnet)

View File

@ -9,4 +9,4 @@
import Foundation
import ZcashLightClientKit
let ZCASH_NETWORK = ZcashNetworkBuilder.network(for: .testnet)
let kZcashNetwork = ZcashNetworkBuilder.network(for: .testnet)

View File

@ -9,7 +9,8 @@
import Foundation
import ZcashLightClientKit
import MnemonicSwift
struct DemoAppConfig {
// swiftlint:disable line_length force_try
enum DemoAppConfig {
static var host = ZcashSDK.isMainnet ? "lightwalletd.electriccoin.co" : "lightwalletd.testnet.electriccoin.co"
static var port: Int = 9067
static var birthdayHeight: BlockHeight = ZcashSDK.isMainnet ? 935000 : 1386000
@ -20,7 +21,7 @@ struct DemoAppConfig {
}
static var processorConfig: CompactBlockProcessor.Configuration = {
CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), walletBirthday: Self.birthdayHeight, network: ZCASH_NETWORK)
CompactBlockProcessor.Configuration(cacheDb: try! cacheDbURLHelper(), dataDb: try! dataDbURLHelper(), walletBirthday: Self.birthdayHeight, network: kZcashNetwork)
}()
static var endpoint: LightWalletEndpoint {
@ -31,7 +32,7 @@ struct DemoAppConfig {
extension ZcashSDK {
static var isMainnet: Bool {
switch ZCASH_NETWORK.networkType {
switch kZcashNetwork.networkType {
case .mainnet:
return true
case .testnet:

View File

@ -83,7 +83,7 @@ class DerivationToolViewController: UIViewController {
func deriveFrom(seedPhrase: String) throws {
let seedBytes = try Mnemonic.deterministicSeedBytes(from: seedPhrase)
let derivationTool = DerivationTool(networkType: ZCASH_NETWORK.networkType)
let derivationTool = DerivationTool(networkType: kZcashNetwork.networkType)
guard let spendingKey = try derivationTool.deriveSpendingKeys(seed: seedBytes, numberOfAccounts: 1).first else {
throw DerivationErrors.couldNotDeriveSpendingKeys(underlyingError: DerivationErrors.unknown)
}

View File

@ -15,7 +15,7 @@ class GetAddressViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let derivationTool = DerivationTool(networkType: ZCASH_NETWORK.networkType)
let derivationTool = DerivationTool(networkType: kZcashNetwork.networkType)
// Do any additional setup after loading the view.
zAddressLabel.text = (try? derivationTool.deriveShieldedAddress(seed: DemoAppConfig.seed, accountIndex: 0)) ?? "No Addresses found"
@ -60,7 +60,7 @@ class GetAddressViewController: UIViewController {
@IBAction func addressTapped(_ gesture: UIGestureRecognizer) {
loggerProxy.event("copied to clipboard")
UIPasteboard.general.string = try? DerivationTool(networkType: ZCASH_NETWORK.networkType).deriveShieldedAddress(seed: DemoAppConfig.seed, accountIndex: 0)
UIPasteboard.general.string = try? DerivationTool(networkType: kZcashNetwork.networkType).deriveShieldedAddress(seed: DemoAppConfig.seed, accountIndex: 0)
let alert = UIAlertController(title: "", message: "Address Copied to clipboard", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
@ -68,7 +68,7 @@ class GetAddressViewController: UIViewController {
@IBAction func tAddressTapped(_ gesture: UIGestureRecognizer) {
loggerProxy.event("copied to clipboard")
UIPasteboard.general.string = try? DerivationTool(networkType: ZCASH_NETWORK.networkType).deriveTransparentAddress(seed: DemoAppConfig.seed)
UIPasteboard.general.string = try? DerivationTool(networkType: kZcashNetwork.networkType).deriveTransparentAddress(seed: DemoAppConfig.seed)
let alert = UIAlertController(title: "", message: "Address Copied to clipboard", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)

View File

@ -35,12 +35,12 @@ class GetBalanceViewController: UIViewController {
extension Int64 {
func asHumanReadableZecBalance() -> Double {
Double(self) / Double(ZcashSDK.ZATOSHI_PER_ZEC)
Double(self) / Double(ZcashSDK.zatoshiPerZEC)
}
}
extension Double {
func toZatoshi() -> Int64 {
Int64(self * Double(ZcashSDK.ZATOSHI_PER_ZEC))
Int64(self * Double(ZcashSDK.zatoshiPerZEC))
}
}

View File

@ -26,7 +26,7 @@ class GetUTXOsViewController: UIViewController {
}
func updateUI() {
let tAddress = try! DerivationTool(networkType: ZCASH_NETWORK.networkType).deriveTransparentAddress(seed: DemoAppConfig.seed)
let tAddress = try! DerivationTool(networkType: kZcashNetwork.networkType).deriveTransparentAddress(seed: DemoAppConfig.seed)
self.transparentAddressLabel.text = tAddress
let balance = try! AppDelegate.shared.sharedSynchronizer.getTransparentBalance(accountIndex: 0)
@ -38,7 +38,7 @@ class GetUTXOsViewController: UIViewController {
@IBAction func shieldFunds(_ sender: Any) {
do {
let seed = DemoAppConfig.seed
let derivationTool = DerivationTool(networkType: ZCASH_NETWORK.networkType)
let derivationTool = DerivationTool(networkType: kZcashNetwork.networkType)
let sk = try derivationTool.deriveSpendingKeys(seed: seed, numberOfAccounts: 1).first!
let tsk = try derivationTool.deriveTransparentPrivateKey(seed: seed)

View File

@ -5,12 +5,11 @@
// Created by Francisco Gindre on 12/20/19.
// Copyright © 2019 Electric Coin Company. All rights reserved.
//
// swiftlint:disable line_length force_try
import Foundation
protocol WalletStorage {
var seed: Data? {get set}
var seed: Data? { get set }
var privateKey: String? { get set }
}
@ -25,24 +24,23 @@ class SampleStorage: WalletStorage {
static var shared: WalletStorage! {
_shared
}
private let KEY_SEED = "cash.z.wallet.sdk.demoapp.SEED"
private let KEY_PK = "cash.z.wallet.sdk.demoapp.PK"
private let keySeed = "cash.z.wallet.sdk.demoapp.SEED"
private let keyPK = "cash.z.wallet.sdk.demoapp.PK"
var seed: Data? {
set {
UserDefaults.standard.set(newValue, forKey: KEY_SEED)
UserDefaults.standard.set(newValue, forKey: keySeed)
}
get {
UserDefaults.standard.value(forKey: KEY_SEED) as! Data?
UserDefaults.standard.value(forKey: keySeed) as! Data?
}
}
var privateKey: String? {
set {
UserDefaults.standard.set(newValue, forKey: KEY_PK)
UserDefaults.standard.set(newValue, forKey: keyPK)
}
get {
UserDefaults.standard.value(forKey: KEY_PK) as! String?
UserDefaults.standard.value(forKey: keyPK) as! String?
}
}
}

View File

@ -15,8 +15,8 @@ class SaplingParametersViewController: UIViewController {
@IBOutlet weak var deleteButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
let spendParamPath = try! __spendParamsURL().path
let outputParamPath = try! __outputParamsURL().path
let spendParamPath = try! spendParamsURLHelper().path
let outputParamPath = try! outputParamsURLHelper().path
// Do any additional setup after loading the view.
self.spendPath.text = spendParamPath
self.outputPath.text = outputParamPath
@ -29,14 +29,14 @@ class SaplingParametersViewController: UIViewController {
self.updateButtons()
}
func updateButtons() {
let spendParamPath = try! __spendParamsURL().path
let outputParamPath = try! __outputParamsURL().path
let spendParamPath = try! spendParamsURLHelper().path
let outputParamPath = try! outputParamsURLHelper().path
self.downloadButton.isHidden = fileExists(outputParamPath) && fileExists(spendParamPath)
self.deleteButton.isHidden = !(fileExists(outputParamPath) || fileExists(spendParamPath))
}
func updateColor() {
let spendParamPath = try! __spendParamsURL().path
let outputParamPath = try! __outputParamsURL().path
let spendParamPath = try! spendParamsURLHelper().path
let outputParamPath = try! outputParamsURLHelper().path
self.spendPath.textColor = fileExists(spendParamPath) ? UIColor.green : UIColor.red
self.outputPath.textColor = fileExists(outputParamPath) ? UIColor.green : UIColor.red
}
@ -57,8 +57,8 @@ class SaplingParametersViewController: UIViewController {
}
@IBAction func download(_ sender: Any) {
let outputParameter = try! __outputParamsURL()
let spendParameter = try! __spendParamsURL()
let outputParameter = try! outputParamsURLHelper()
let spendParameter = try! spendParamsURLHelper()
SaplingParameterDownloader.downloadParamsIfnotPresent(spendURL: spendParameter, outputURL: outputParameter) { (result) in
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
@ -87,8 +87,8 @@ class SaplingParametersViewController: UIViewController {
}
@IBAction func deleteFiles(_ sender: Any) {
let spendParamURL = try! __spendParamsURL()
let outputParamURL = try! __outputParamsURL()
let spendParamURL = try! spendParamsURLHelper()
let outputParamURL = try! outputParamsURLHelper()
try? FileManager.default.removeItem(at: spendParamURL)
try? FileManager.default.removeItem(at: outputParamURL)

View File

@ -173,8 +173,13 @@ class SendViewController: UIViewController {
KRProgressHUD.show()
synchronizer.sendToAddress(spendingKey: address, zatoshi: zec, toAddress: recipient, memo: self.memoField.text.count > 0 ? self.memoField.text : nil, from: 0) { [weak self] result in
synchronizer.sendToAddress(
spendingKey: address,
zatoshi: zec,
toAddress: recipient,
memo: !self.memoField.text.isEmpty ? self.memoField.text : nil,
from: 0
) { [weak self] result in
DispatchQueue.main.async {
KRProgressHUD.dismiss()
}

View File

@ -37,13 +37,13 @@ class CompactBlockStorage: CompactBlockDAO {
let db = try dbProvider.connection()
try db.run(compactBlocks.create(ifNotExists: true) { t in
t.column(height, primaryKey: true)
t.column(data)
} )
try db.run(compactBlocks.create(ifNotExists: true) { table in
table.column(height, primaryKey: true)
table.column(data)
}
)
try db.run(compactBlocks.createIndex(height, ifNotExists: true))
} catch {
throw StorageError.couldNotCreate
}
@ -64,7 +64,6 @@ class CompactBlockStorage: CompactBlockDAO {
}
func latestBlockHeight() throws -> BlockHeight {
guard let maxHeight = try dbProvider.connection().scalar(compactBlocksTable().select(heightColumn().max)) else {
return BlockHeight.empty()
}
@ -82,7 +81,6 @@ class CompactBlockStorage: CompactBlockDAO {
}
extension CompactBlockStorage: CompactBlockRepository {
func latestHeight() throws -> BlockHeight {
try latestBlockHeight()
}
@ -117,11 +115,9 @@ extension CompactBlockStorage: CompactBlockRepository {
do {
try self.rewind(to: height)
completion?(nil)
} catch {
completion?(error)
}
}
}
}

View File

@ -59,7 +59,7 @@ class MigrationManager {
}
}
fileprivate func migrateCacheDb() throws {
private func migrateCacheDb() throws {
let currentCacheDbVersion = try cacheDb.connection().getUserVersion()
LoggerProxy.debug("Attempting to perform migration for cache Db - currentVersion: \(currentCacheDbVersion). Latest version is: \(Self.latestCacheDbMigrationVersion)")
@ -72,15 +72,17 @@ class MigrationManager {
}
}
fileprivate func migrateDataDb(uvks: [UnifiedViewingKey]) throws {
private func migrateDataDb(uvks: [UnifiedViewingKey]) throws {
let currentDataDbVersion = try dataDb.connection().getUserVersion()
LoggerProxy.debug("Attempting to perform migration for data Db - currentVersion: \(currentDataDbVersion). Latest version is: \(Self.latestDataDbMigrationVersion)")
LoggerProxy.debug(
"Attempting to perform migration for data Db - currentVersion: \(currentDataDbVersion). Latest version is: \(Self.latestDataDbMigrationVersion)" // swiftlint:disable line_length
)
if currentDataDbVersion < Self.latestDataDbMigrationVersion {
for v in (currentDataDbVersion + 1) ... Self.latestDataDbMigrationVersion {
guard let version = DataDbMigrations.init(rawValue: v) else {
for version in (currentDataDbVersion + 1) ... Self.latestDataDbMigrationVersion {
guard let version = DataDbMigrations.init(rawValue: version) else {
LoggerProxy.error("failed to determine migration version")
throw StorageError.invalidMigrationVersion(version: v)
throw StorageError.invalidMigrationVersion(version: version)
}
switch version {
case .version1:
@ -95,7 +97,9 @@ class MigrationManager {
}
func performVersion1Migration(viewingKeys: [UnifiedViewingKey]) throws {
LoggerProxy.debug("Starting migration version 1 from viewing Keys")
LoggerProxy.debug(
"Starting migration version 1 from viewing Keys"
)
let db = try self.dataDb.connection()
let placeholder = "deriveMe"
@ -147,7 +151,10 @@ class MigrationManager {
}
guard accounts.count == viewingKeys.count else {
let message = "Number of accounts found and viewing keys provided don't match. Found \(accounts.count) account(s) and there were \(viewingKeys.count) Viewing key(s) provided."
let message = """
Number of accounts found and viewing keys provided don't match.
Found \(accounts.count) account(s) and there were \(viewingKeys.count) Viewing key(s) provided.
"""
LoggerProxy.debug(message)
throw StorageError.migrationFailedWithMessage(message: message)
}
@ -189,10 +196,10 @@ class MigrationManager {
extension Connection {
func getUserVersion() throws -> Int32 {
guard let v = try scalar("PRAGMA user_version") as? Int64 else {
guard let version = try scalar("PRAGMA user_version") as? Int64 else {
return 0
}
return Int32(v)
return Int32(version)
}
func setUserVersion(_ version: Int32) throws {

View File

@ -55,7 +55,6 @@ private extension Connection {
}
class SimpleConnectionProvider: ConnectionProvider {
var path: String
var readonly: Bool
var db: Connection?
@ -66,12 +65,11 @@ class SimpleConnectionProvider: ConnectionProvider {
}
func connection() throws -> Connection {
guard let c = db else {
let c = try Connection(path, readonly: readonly)
self.db = c
return c
guard let conn = db else {
let conn = try Connection(path, readonly: readonly)
self.db = conn
return conn
}
return c
return conn
}
}

View File

@ -196,14 +196,12 @@ extension CompactBlockDownloader: CompactBlockDownloading {
}
func rewind(to height: BlockHeight, completion: @escaping (Error?) -> Void) {
storage.rewind(to: height) { (e) in
completion(e)
}
}
func lastDownloadedBlockHeight(result: @escaping (Result<BlockHeight,Error>) -> Void) {
storage.latestHeight { (r) in
switch r {
case .failure(let e):
@ -223,12 +221,12 @@ extension CompactBlockDownloader: CompactBlockDownloading {
try self.storage.latestHeight()
}
func fetchTransaction(txId: Data) throws -> TransactionEntity{
func fetchTransaction(txId: Data) throws -> TransactionEntity {
try lightwalletService.fetchTransaction(txId: txId)
}
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, Error>) -> Void) {
lightwalletService.fetchTransaction(txId: txId) { (txResult) in
lightwalletService.fetchTransaction(txId: txId) { txResult in
switch txResult {
case .failure(let error):
result(.failure(error))

View File

@ -81,7 +81,6 @@ class CompactBlockStreamDownloadOperation: ZcashOperation {
}
self.startedHandler?()
do {
if self.targetHeight == nil {
self.targetHeight = try service.latestBlockHeight()
}
@ -93,7 +92,6 @@ class CompactBlockStreamDownloadOperation: ZcashOperation {
self.cancelable = self.service.blockStream(startHeight: startHeight, endHeight: latestHeight) { [weak self] result in
switch result {
case .success(let r):
switch r {
case .ok:
@ -109,7 +107,6 @@ class CompactBlockStreamDownloadOperation: ZcashOperation {
self?.fail(error: e)
}
}
} handler: {[weak self] block in
guard let self = self else { return }
do {
@ -156,14 +153,15 @@ class CompactBlockBatchDownloadOperation: ZcashOperation {
private var startHeight: BlockHeight
private var targetHeight: BlockHeight
private weak var progressDelegate: CompactBlockProgressDelegate?
required init(service: LightWalletService,
storage: CompactBlockStorage,
startHeight: BlockHeight,
targetHeight: BlockHeight,
batchSize: Int = 100,
maxRetries: Int = 5,
progressDelegate: CompactBlockProgressDelegate? = nil) {
required init(
service: LightWalletService,
storage: CompactBlockStorage,
startHeight: BlockHeight,
targetHeight: BlockHeight,
batchSize: Int = 100,
maxRetries: Int = 5,
progressDelegate: CompactBlockProgressDelegate? = nil
) {
self.storage = storage
self.service = service
self.startHeight = startHeight
@ -182,7 +180,6 @@ class CompactBlockBatchDownloadOperation: ZcashOperation {
}
self.startedHandler?()
do {
let localDownloadedHeight = try self.storage.latestHeight()
if localDownloadedHeight != BlockHeight.empty() && localDownloadedHeight > startHeight {
@ -196,7 +193,7 @@ class CompactBlockBatchDownloadOperation: ZcashOperation {
while !isCancelled && currentHeight <= targetHeight {
var retries = 0
var success = true
var localError: Error? = nil
var localError: Error?
let range = nextRange(currentHeight: currentHeight, targetHeight: targetHeight)
@ -205,18 +202,25 @@ class CompactBlockBatchDownloadOperation: ZcashOperation {
let blocks = try service.blockRange(range)
try storage.insert(blocks)
success = true
} catch {
success = false
localError = error
retries = retries + 1
retries += 1
}
} while !isCancelled && !success && retries < maxRetries
if retries >= maxRetries {
throw CompactBlockBatchDownloadOperationError.batchDownloadFailed(range: range, error: localError)
}
self.progressDelegate?.progressUpdated(.download(BlockProgress(startHeight: startHeight, targetHeight: targetHeight, progressHeight: range.upperBound)))
self.progressDelegate?.progressUpdated(
.download(
BlockProgress(
startHeight: startHeight,
targetHeight: targetHeight,
progressHeight: range.upperBound
)
)
)
currentHeight = range.upperBound + 1
}
} catch {

View File

@ -56,25 +56,27 @@ class CompactBlockEnhancementOperation: ZcashOperation {
// fetch transactions
do {
guard let transactions = try repository.findTransactions(in: self.range, limit: Int.max), transactions.count > 0 else {
guard let transactions = try repository.findTransactions(in: self.range, limit: Int.max), !transactions.isEmpty else {
LoggerProxy.debug("no transactions detected on range: \(range.printRange)")
return
}
for index in 0 ..< transactions.count {
let tx = transactions[index]
let transaction = transactions[index]
var retry = true
while retry && self.retries < maxRetries {
do {
let confirmedTx = try enhance(transaction: tx)
let confirmedTx = try enhance(transaction: transaction)
retry = false
self.reportProgress(totalTransactions: transactions.count,
enhanced: index + 1,
txEnhanced: confirmedTx)
self.reportProgress(
totalTransactions: transactions.count,
enhanced: index + 1,
txEnhanced: confirmedTx
)
} catch {
self.retries = self.retries + 1
LoggerProxy.error("could not enhance txId \(tx.transactionId.toHexStringTxId()) - Error: \(error)")
self.retries += 1
LoggerProxy.error("could not enhance txId \(transaction.transactionId.toHexStringTxId()) - Error: \(error)")
if retries > maxRetries {
throw error
}
@ -94,34 +96,42 @@ class CompactBlockEnhancementOperation: ZcashOperation {
}
func reportProgress(totalTransactions: Int, enhanced: Int, txEnhanced: ConfirmedTransactionEntity) {
self.progressDelegate?.progressUpdated(.enhance(
EnhancementStreamProgress(
totalTransactions: totalTransactions,
enhancedTransactions: enhanced,
lastFoundTransaction: txEnhanced,
range: self.range.compactBlockRange)))
self.progressDelegate?.progressUpdated(
.enhance(
EnhancementStreamProgress(
totalTransactions: totalTransactions,
enhancedTransactions: enhanced,
lastFoundTransaction: txEnhanced,
range: self.range.compactBlockRange
)
)
)
}
func enhance(transaction: TransactionEntity) throws -> ConfirmedTransactionEntity {
LoggerProxy.debug("Zoom.... Enhance... Tx: \(transaction.transactionId.toHexStringTxId())")
let tx = try downloader.fetchTransaction(txId: transaction.transactionId)
let transaction = try downloader.fetchTransaction(txId: transaction.transactionId)
LoggerProxy.debug("Decrypting and storing transaction id: \(tx.transactionId.toHexStringTxId()) block: \(String(describing: tx.minedHeight))")
LoggerProxy.debug("Decrypting and storing transaction id: \(transaction.transactionId.toHexStringTxId()) block: \(String(describing: transaction.minedHeight))")
guard let rawBytes = tx.raw?.bytes else {
let error = EnhancementError.noRawData(message: "Critical Error: transaction id: \(tx.transactionId.toHexStringTxId()) has no data")
guard let rawBytes = transaction.raw?.bytes else {
let error = EnhancementError.noRawData(
message: "Critical Error: transaction id: \(transaction.transactionId.toHexStringTxId()) has no data"
)
LoggerProxy.error("\(error)")
throw error
}
guard let minedHeight = tx.minedHeight else {
let error = EnhancementError.noRawData(message: "Critical Error - Attempt to decrypt and store an unmined transaction. Id: \(tx.transactionId.toHexStringTxId()) ")
guard let minedHeight = transaction.minedHeight else {
let error = EnhancementError.noRawData(
message: "Critical Error - Attempt to decrypt and store an unmined transaction. Id: \(transaction.transactionId.toHexStringTxId())"
)
LoggerProxy.error("\(error)")
throw error
}
guard rustBackend.decryptAndStoreTransaction(dbData: dataDb, tx: rawBytes, minedHeight: Int32(minedHeight), networkType: network) else {
guard rustBackend.decryptAndStoreTransaction(dbData: dataDb, txBytes: rawBytes, minedHeight: Int32(minedHeight), networkType: network) else {
if let rustError = rustBackend.lastError() {
throw EnhancementError.decryptError(error: rustError)
}

View File

@ -5,6 +5,7 @@
// Created by Francisco Gindre on 18/09/2019.
// Copyright © 2019 Electric Coin Company. All rights reserved.
//
// swiftlint:disable file_length type_body_length
import Foundation
import GRPC
@ -34,7 +35,7 @@ public enum CompactBlockProcessorError: Error {
CompactBlockProcessor notification userInfo object keys.
check Notification.Name extensions for more details.
*/
public struct CompactBlockProcessorNotificationKey {
public enum CompactBlockProcessorNotificationKey {
public static let progress = "CompactBlockProcessorNotificationKey.progress"
// public static let progressStartHeight = "CompactBlockProcessorNotificationKey.progressStartHeight"
// public static let progressTargetHeight = "CompactBlockProcessorNotificationKey.progressTargetHeight"
@ -63,11 +64,11 @@ public enum CompactBlockProgress {
public var progress: Float {
switch self {
case .download(let p),
.scan(let p):
return p.progress
case .enhance(let p):
return p.progress
case .download(let blockProgress),
.scan(let blockProgress):
return blockProgress.progress
case .enhance(let enhancementProgress):
return enhancementProgress.progress
default:
return 0
}
@ -75,18 +76,19 @@ public enum CompactBlockProgress {
public var progressHeight: BlockHeight? {
switch self {
case .download(let p),
.scan(let p):
return p.progressHeight
case .enhance(let p):
return p.lastFoundTransaction?.minedHeight
case .download(let blockProgress),
.scan(let blockProgress):
return blockProgress.progressHeight
case .enhance(let enhancementProgress):
return enhancementProgress.lastFoundTransaction?.minedHeight
default:
return 0
}
}
public var blockDate: Date? {
if case .enhance(let p ) = self, let time = p.lastFoundTransaction?.blockTimeInSeconds {
if case .enhance(let enhancementProgress) = self,
let time = enhancementProgress.lastFoundTransaction?.blockTimeInSeconds {
return Date(timeIntervalSince1970: time)
}
return nil
@ -94,8 +96,8 @@ public enum CompactBlockProgress {
public var targetHeight: BlockHeight? {
switch self {
case .download(let p), .scan(let p):
return p.targetHeight
case .download(let blockProgress), .scan(let blockProgress):
return blockProgress.targetHeight
default:
return nil
}
@ -201,7 +203,6 @@ public extension Notification.Name {
Notification sent when the grpc service connection detects a change. Query the user info object for status change details `currentConnectivityStatus` for current and previous with `previousConnectivityStatus`
*/
static let blockProcessorConnectivityStateChanged = Notification.Name("CompactBlockProcessorConnectivityStateChanged")
}
/**
@ -219,14 +220,14 @@ public class CompactBlockProcessor {
public struct Configuration {
public var cacheDb: URL
public var dataDb: URL
public var downloadBatchSize = ZcashSDK.DEFAULT_BATCH_SIZE
public var downloadBatchSize = ZcashSDK.DefaultBatchSize
public var blockPollInterval: TimeInterval {
TimeInterval.random(in: ZcashSDK.DEFAULT_POLL_INTERVAL / 2 ... ZcashSDK.DEFAULT_POLL_INTERVAL * 1.5)
TimeInterval.random(in: ZcashSDK.defaultPollInterval / 2 ... ZcashSDK.defaultPollInterval * 1.5)
}
public var retries = ZcashSDK.DEFAULT_RETRIES
public var maxBackoffInterval = ZcashSDK.DEFAULT_MAX_BACKOFF_INTERVAL
public var rewindDistance = ZcashSDK.DEFAULT_REWIND_DISTANCE
public var retries = ZcashSDK.defaultRetries
public var maxBackoffInterval = ZcashSDK.defaultMaxBackOffInterval
public var rewindDistance = ZcashSDK.defaultRewindDistance
public var walletBirthday: BlockHeight
private(set) var network: ZcashNetwork
private(set) var saplingActivation: BlockHeight
@ -257,7 +258,7 @@ public class CompactBlockProcessor {
self.cacheDb = cacheDb
self.dataDb = dataDb
self.walletBirthday = walletBirthday
self.saplingActivation = network.constants.SAPLING_ACTIVATION_HEIGHT
self.saplingActivation = network.constants.saplingActivationHeight
self.network = network
}
}
@ -322,12 +323,12 @@ public class CompactBlockProcessor {
self.stop()
}
}
private var queue: OperationQueue = {
let q = OperationQueue()
q.name = "CompactBlockProcessorQueue"
q.maxConcurrentOperationCount = 1
return q
} ()
private var operationQueue: OperationQueue = {
let queue = OperationQueue()
queue.name = "CompactBlockProcessorQueue"
queue.maxConcurrentOperationCount = 1
return queue
}()
private var retryAttempts: Int = 0
private var backoffTimer: Timer?
@ -352,7 +353,7 @@ public class CompactBlockProcessor {
- Throws CompactBlockProcessorError.invalidConfiguration if block height is invalid or if processor is already started
*/
func setStartHeight(_ startHeight: BlockHeight) throws {
guard self.state == .stopped, startHeight >= config.network.constants.SAPLING_ACTIVATION_HEIGHT else {
guard self.state == .stopped, startHeight >= config.network.constants.saplingActivationHeight else {
throw CompactBlockProcessorError.invalidConfiguration
}
@ -367,16 +368,21 @@ public class CompactBlockProcessor {
- downloader: an instance that complies to CompactBlockDownloading protocol
- backend: a class that complies to ZcashRustBackendWelding
*/
convenience init(service: LightWalletService,
storage: CompactBlockStorage,
backend: ZcashRustBackendWelding.Type,
config: Configuration) {
self.init(service: service,
storage: storage,
backend: backend,
config: config,
repository: TransactionRepositoryBuilder.build(dataDbURL: config.dataDb),
accountRepository: AccountRepositoryBuilder.build(dataDbURL: config.dataDb, readOnly: true))
convenience init(
service: LightWalletService,
storage: CompactBlockStorage,
backend: ZcashRustBackendWelding.Type,
config: Configuration
) {
self.init(
service: service,
storage: storage,
backend: backend,
config: config,
repository: TransactionRepositoryBuilder.build(
dataDbURL: config.dataDb
),
accountRepository: AccountRepositoryBuilder.build(dataDbURL: config.dataDb, readOnly: true))
}
/**
@ -385,24 +391,28 @@ public class CompactBlockProcessor {
- initializer: an instance that complies to CompactBlockDownloading protocol
*/
public convenience init(initializer: Initializer) {
self.init(service: initializer.lightWalletService,
storage: initializer.storage,
backend: initializer.rustBackend,
config: Configuration(cacheDb: initializer.cacheDbURL,
dataDb: initializer.dataDbURL,
walletBirthday: initializer.walletBirthday.height,
network: initializer.network),
repository: initializer.transactionRepository,
accountRepository: initializer.accountRepository)
self.init(
service: initializer.lightWalletService,
storage: initializer.storage,
backend: initializer.rustBackend,
config: Configuration(
cacheDb: initializer.cacheDbURL,
dataDb: initializer.dataDbURL,
walletBirthday: initializer.walletBirthday.height,
network: initializer.network
),
repository: initializer.transactionRepository,
accountRepository: initializer.accountRepository)
}
internal init(service: LightWalletService,
storage: CompactBlockStorage,
backend: ZcashRustBackendWelding.Type,
config: Configuration,
repository: TransactionRepository,
accountRepository: AccountRepository) {
internal init(
service: LightWalletService,
storage: CompactBlockStorage,
backend: ZcashRustBackendWelding.Type,
config: Configuration,
repository: TransactionRepository,
accountRepository: AccountRepository
) {
self.service = service
self.downloader = CompactBlockDownloader(service: service, storage: storage)
self.rustBackend = backend
@ -414,7 +424,7 @@ public class CompactBlockProcessor {
}
deinit {
self.queue.cancelAllOperations()
self.operationQueue.cancelAllOperations()
}
var maxAttemptsReached: Bool {
@ -447,7 +457,6 @@ public class CompactBlockProcessor {
*/
public func start(retry: Bool = false) throws {
// TODO: check if this validation makes sense at all
// try validateConfiguration()
if retry {
@ -456,9 +465,9 @@ public class CompactBlockProcessor {
self.backoffTimer?.invalidate()
self.backoffTimer = nil
}
guard !queue.isSuspended else {
guard !operationQueue.isSuspended else {
LoggerProxy.debug("restarting suspended queue")
queue.isSuspended = false
operationQueue.isSuspended = false
return
}
@ -487,7 +496,6 @@ public class CompactBlockProcessor {
}
func validateServer(completionBlock: @escaping (() -> Void)) {
self.service.getInfo(result: { [weak self] result in
guard let self = self else { return }
@ -496,10 +504,12 @@ public class CompactBlockProcessor {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
do {
try Self.validateServerInfo(info,
saplingActivation: self.config.saplingActivation,
localNetwork: self.config.network,
rustBackend: self.rustBackend)
try Self.validateServerInfo(
info,
saplingActivation: self.config.saplingActivation,
localNetwork: self.config.network,
rustBackend: self.rustBackend
)
completionBlock()
} catch {
self.severeFailure(error)
@ -511,14 +521,18 @@ public class CompactBlockProcessor {
})
}
static func validateServerInfo(_ info: LightWalletdInfo,
saplingActivation: BlockHeight,
localNetwork: ZcashNetwork,
rustBackend: ZcashRustBackendWelding.Type) throws {
static func validateServerInfo(
_ info: LightWalletdInfo,
saplingActivation: BlockHeight,
localNetwork: ZcashNetwork,
rustBackend: ZcashRustBackendWelding.Type) throws {
// check network types
guard let remoteNetworkType = NetworkType.forChainName(info.chainName) else {
throw CompactBlockProcessorError.generalError(message: "Chain name does not match. Expected either 'test' or 'main' but received '\(info.chainName)'. this is probably an API or programming error")
throw CompactBlockProcessorError
.generalError(
message: "Chain name does not match. Expected either 'test' or 'main' but received '\(info.chainName)'. this is probably an API or programming error"
)
}
guard remoteNetworkType == localNetwork.networkType else {
@ -539,8 +553,7 @@ public class CompactBlockProcessor {
guard remoteBranchID == localBranch else {
throw CompactBlockProcessorError.wrongConsensusBranchId(expectedLocally: localBranch, found: remoteBranchID)
}
}
}
/**
@ -553,9 +566,9 @@ public class CompactBlockProcessor {
self.backoffTimer?.invalidate()
self.backoffTimer = nil
if cancelTasks {
queue.cancelAllOperations()
operationQueue.cancelAllOperations()
} else {
self.queue.isSuspended = true
self.operationQueue.isSuspended = true
}
self.retryAttempts = 0
@ -705,7 +718,15 @@ public class CompactBlockProcessor {
}
}
let scanBlocksOperation = CompactBlockBatchScanningOperation(rustWelding: rustBackend, cacheDb: config.cacheDb, dataDb: config.dataDb, transactionRepository: transactionRepository, range: range, networkType: self.config.network.networkType, progressDelegate: self)
let scanBlocksOperation = CompactBlockBatchScanningOperation(
rustWelding: rustBackend,
cacheDb: config.cacheDb,
dataDb: config.dataDb,
transactionRepository: transactionRepository,
range: range,
networkType: self.config.network.networkType,
progressDelegate: self
)
let validateScanningAdapterOperation = BlockOperation { [weak scanBlocksOperation, weak validateChainOperation] in
scanBlocksOperation?.error = validateChainOperation?.error
@ -716,7 +737,7 @@ public class CompactBlockProcessor {
}
}
scanBlocksOperation.completionHandler = { [weak self] (finished, cancelled) in
scanBlocksOperation.completionHandler = { [weak self] finished, cancelled in
guard !cancelled else {
DispatchQueue.main.async { [weak self] in
self?.state = .stopped
@ -726,7 +747,7 @@ public class CompactBlockProcessor {
}
}
scanBlocksOperation.errorHandler = { [weak self] (error) in
scanBlocksOperation.errorHandler = { [weak self] error in
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
self.processingError = error
@ -734,7 +755,14 @@ public class CompactBlockProcessor {
}
}
let enhanceOperation = CompactBlockEnhancementOperation(rustWelding: rustBackend, dataDb: config.dataDb, downloader: downloader, repository: transactionRepository, range: range.blockRange(), networkType: self.config.network.networkType)
let enhanceOperation = CompactBlockEnhancementOperation(
rustWelding: rustBackend,
dataDb: config.dataDb,
downloader: downloader,
repository: transactionRepository,
range: range.blockRange(),
networkType: self.config.network.networkType
)
enhanceOperation.startedHandler = {
LoggerProxy.debug("Started Enhancing range: \(range)")
@ -743,18 +771,18 @@ public class CompactBlockProcessor {
}
}
enhanceOperation.txFoundHandler = { [weak self] (txs,range) in
self?.notifyTransactions(txs,in: range)
enhanceOperation.txFoundHandler = { [weak self] txs, range in
self?.notifyTransactions(txs, in: range)
}
enhanceOperation.completionHandler = { (finished, cancelled) in
enhanceOperation.completionHandler = { finished, cancelled in
guard !cancelled else {
LoggerProxy.debug("Warning: enhance operation on range \(range) cancelled")
return
}
}
enhanceOperation.errorHandler = { [weak self] (error) in
enhanceOperation.errorHandler = { [weak self] error in
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
@ -767,7 +795,14 @@ public class CompactBlockProcessor {
enhanceOperation?.error = scanBlocksOperation?.error
}
let fetchOperation = FetchUnspentTxOutputsOperation(accountRepository: accountRepository, downloader: self.downloader, rustbackend: rustBackend, dataDb: config.dataDb, startHeight: config.walletBirthday, networkType: self.config.network.networkType)
let fetchOperation = FetchUnspentTxOutputsOperation(
accountRepository: accountRepository,
downloader: self.downloader,
rustbackend: rustBackend,
dataDb: config.dataDb,
startHeight: config.walletBirthday,
networkType: self.config.network.networkType
)
fetchOperation.startedHandler = { [weak self] in
DispatchQueue.main.async { [weak self] in
@ -775,7 +810,7 @@ public class CompactBlockProcessor {
}
}
fetchOperation.completionHandler = { [weak self] (finished, cancelled) in
fetchOperation.completionHandler = { [weak self] finished, cancelled in
guard !cancelled else {
LoggerProxy.debug("Warning: fetch operation on range \(range) cancelled")
return
@ -784,7 +819,7 @@ public class CompactBlockProcessor {
self?.processBatchFinished(range: range)
}
}
fetchOperation.errorHandler = { [weak self] (error) in
fetchOperation.errorHandler = { [weak self] error in
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
@ -809,7 +844,7 @@ public class CompactBlockProcessor {
enhanceFetchAdapterOperation.addDependency(enhanceOperation)
fetchOperation.addDependency(enhanceFetchAdapterOperation)
queue.addOperations([downloadBlockOperation,
operationQueue.addOperations([downloadBlockOperation,
downloadValidateAdapterOperation,
validateChainOperation,
validateScanningAdapterOperation,
@ -853,15 +888,19 @@ public class CompactBlockProcessor {
private func validationFailed(at height: BlockHeight) {
// cancel all Tasks
queue.cancelAllOperations()
operationQueue.cancelAllOperations()
// register latest failure
self.lastChainValidationFailure = height
self.consecutiveChainValidationErrors = self.consecutiveChainValidationErrors + 1
self.consecutiveChainValidationErrors += 1
// rewind
let rewindHeight = determineLowerBound(errorHeight: height, consecutiveErrors: consecutiveChainValidationErrors, walletBirthday: self.config.walletBirthday)
let rewindHeight = determineLowerBound(
errorHeight: height,
consecutiveErrors: consecutiveChainValidationErrors,
walletBirthday: self.config.walletBirthday
)
guard rustBackend.rewindToHeight(dbData: config.dataDb, height: Int32(rewindHeight), networkType: self.config.network.networkType) else {
fail(rustBackend.lastError() ?? RustWeldingError.genericError(message: "unknown error rewinding to height \(height)"))
return
@ -871,7 +910,13 @@ public class CompactBlockProcessor {
try downloader.rewind(to: rewindHeight)
// notify reorg
NotificationCenter.default.post(name: Notification.Name.blockProcessorHandledReOrg, object: self, userInfo: [CompactBlockProcessorNotificationKey.reorgHeight : height, CompactBlockProcessorNotificationKey.rewindHeight : rewindHeight])
NotificationCenter.default.post(
name: Notification.Name.blockProcessorHandledReOrg,
object: self,
userInfo: [
CompactBlockProcessorNotificationKey.reorgHeight: height, CompactBlockProcessorNotificationKey.rewindHeight: rewindHeight
]
)
// process next batch
self.nextBatch()
@ -880,13 +925,16 @@ public class CompactBlockProcessor {
}
}
func determineLowerBound(errorHeight: Int, consecutiveErrors: Int, walletBirthday: BlockHeight) -> BlockHeight {
let offset = min(ZcashSDK.MAX_REORG_SIZE, ZcashSDK.DEFAULT_REWIND_DISTANCE * (consecutiveErrors + 1))
return max(errorHeight - offset, walletBirthday - ZcashSDK.MAX_REORG_SIZE)
func determineLowerBound(
errorHeight: Int,
consecutiveErrors: Int,
walletBirthday: BlockHeight
) -> BlockHeight {
let offset = min(ZcashSDK.maxReorgSize, ZcashSDK.defaultRewindDistance * (consecutiveErrors + 1))
return max(errorHeight - offset, walletBirthday - ZcashSDK.maxReorgSize)
}
private func processBatchFinished(range: CompactBlockRange) {
guard processingError == nil else {
retryProcessing(range: range)
return
@ -908,9 +956,10 @@ public class CompactBlockProcessor {
name: Notification.Name.blockProcessorFinished,
object: self,
userInfo: [
CompactBlockProcessorNotificationKey.latestScannedBlockHeight : height,
CompactBlockProcessorNotificationKey.foundBlocks : self.foundBlocks
])
CompactBlockProcessorNotificationKey.latestScannedBlockHeight: height,
CompactBlockProcessorNotificationKey.foundBlocks: self.foundBlocks
]
)
self.state = .synced
setTimer()
}
@ -923,13 +972,15 @@ public class CompactBlockProcessor {
do {
if self.shouldStart {
LoggerProxy.debug("""
Timer triggered: Starting compact Block processor!.
Processor State: \(self.state)
latestHeight: \(self.latestBlockHeight)
attempts: \(self.retryAttempts)
lowerbound: \(String(describing: self.lowerBoundHeight))
""")
LoggerProxy.debug(
"""
Timer triggered: Starting compact Block processor!.
Processor State: \(self.state)
latestHeight: \(self.latestBlockHeight)
attempts: \(self.retryAttempts)
lowerbound: \(String(describing: self.lowerBoundHeight))
"""
)
try self.start()
} else if self.maxAttemptsReached {
self.fail(CompactBlockProcessorError.maxAttemptsReached(attempts: self.config.retries))
@ -944,7 +995,6 @@ public class CompactBlockProcessor {
}
static func nextBatchBlockRange(latestHeight: BlockHeight, latestDownloadedHeight: BlockHeight, walletBirthday: BlockHeight) -> CompactBlockRange {
let lowerBound = latestDownloadedHeight <= walletBirthday ? walletBirthday : latestDownloadedHeight + 1
let upperBound = latestHeight
@ -952,10 +1002,9 @@ public class CompactBlockProcessor {
}
func retryProcessing(range: CompactBlockRange) {
queue.cancelAllOperations()
operationQueue.cancelAllOperations()
// update retries
self.retryAttempts = self.retryAttempts + 1
self.retryAttempts += 1
self.processingError = nil
guard self.retryAttempts < config.retries else {
self.notifyError(CompactBlockProcessorError.maxAttemptsReached(attempts: self.retryAttempts))
@ -972,25 +1021,23 @@ public class CompactBlockProcessor {
} catch {
self.fail(error)
}
}
func severeFailure(_ error: Error) {
queue.cancelAllOperations()
operationQueue.cancelAllOperations()
LoggerProxy.error("show stoppper failure: \(error)")
self.backoffTimer?.invalidate()
self.retryAttempts = config.retries
self.processingError = error
self.state = .error(error)
self.notifyError(error)
}
func fail(_ error: Error) {
// todo specify: failure
LoggerProxy.error("\(error)")
queue.cancelAllOperations()
self.retryAttempts = self.retryAttempts + 1
operationQueue.cancelAllOperations()
self.retryAttempts += 1
self.processingError = error
switch self.state {
case .error:
@ -1002,7 +1049,6 @@ public class CompactBlockProcessor {
guard self.maxAttemptsReached else { return }
// don't set a new timer if there are no more attempts.
self.setTimer()
}
private func transitionState(from oldValue: State, to newValue: State) {
@ -1125,7 +1171,7 @@ extension CompactBlockProcessor {
guard let account = try? accountRepository.findBy(account: accountIndex) else {
return nil
}
return UnifiedAddressShim(__account: account)
return UnifiedAddressShim(account: account)
}
public func getShieldedAddress(accountIndex: Int) -> SaplingShieldedAddress? {
@ -1144,38 +1190,40 @@ extension CompactBlockProcessor {
}
}
fileprivate struct UnifiedAddressShim {
let __account: AccountEntity
private struct UnifiedAddressShim {
let account: AccountEntity
}
extension UnifiedAddressShim: UnifiedAddress {
var tAddress: TransparentAddress {
get {
__account.transparentAddress
account.transparentAddress
}
}
var zAddress: SaplingShieldedAddress {
get {
__account.address
account.address
}
}
}
extension CompactBlockProcessor {
func refreshUTXOs(tAddress: String, startHeight: BlockHeight, result: @escaping (Result<RefreshedUTXOs,Error>) -> Void) {
let dataDb = self.config.dataDb
self.downloader.fetchUnspentTransactionOutputs(tAddress: tAddress, startHeight: startHeight) { [weak self](r) in
switch r {
case .success(let utxos):
DispatchQueue.main.async {
self?.queue.addOperation { [self] in
self?.operationQueue.addOperation { [self] in
guard let self = self else { return }
do {
guard try self.rustBackend.clearUtxos(dbData: dataDb, address: tAddress, sinceHeight: startHeight - 1, networkType: self.config.network.networkType) >= 0 else {
guard try self.rustBackend.clearUtxos(
dbData: dataDb,
address: tAddress,
sinceHeight: startHeight - 1,
networkType: self.config.network.networkType
) >= 0 else {
result(.failure(CompactBlockProcessorError.generalError(message: "attempted to clear utxos but -1 was returned")))
return
}
@ -1204,7 +1252,8 @@ extension CompactBlockProcessor {
script: utxo.script.bytes,
value: Int64(utxo.valueZat),
height: utxo.height,
networkType: self.config.network.networkType) ? refreshed.append(utxo) : skipped.append(utxo)
networkType: self.config.network.networkType
) ? refreshed.append(utxo) : skipped.append(utxo)
} catch {
LoggerProxy.info("failed to put utxo - error: \(error)")
skipped.append(utxo)
@ -1239,12 +1288,15 @@ extension CompactBlockProcessorError: LocalizedError {
case .missingDbPath(let path):
return "CompactBlockProcessor was set up with path \(path) but thath location couldn't be reached"
case .networkMismatch(let expected, let found):
// swiftlint:disable:next line_length
return "A server was reached, but it's targeting the wrong network Type. App Expected \(expected) but found \(found). Make sure you are pointing to the right server"
case .saplingActivationMismatch(let expected, let found):
// swiftlint:disable:next line_length
return "A server was reached, it's showing a different sapling activation. App expected sapling activation height to be \(expected) but instead it found \(found). Are you sure you are pointing to the right server?"
case .unspecifiedError(let underlyingError):
return "Unspecified error caused by this underlying error: \(underlyingError)"
case .wrongConsensusBranchId(let expectedLocally, let found):
// swiftlint:disable:next line_length
return "The remote server you are connecting to is publishing a different branch ID \(found) than the one your App is expecting to be (\(expectedLocally)). This could be caused by your App being out of date or the server you are connecting you being either on a different network or out of date after a network upgrade."
}
}
@ -1286,24 +1338,24 @@ public extension BlockProgressReporting {
}
extension CompactBlockProcessor {
class NextStateHelper {
static func nextState(service: LightWalletService,
downloader: CompactBlockDownloading,
config: Configuration,
rustBackend: ZcashRustBackendWelding.Type,
queue: DispatchQueue?,
result: @escaping (Result<FigureNextBatchOperation.NextState, Error>) -> Void) {
enum NextStateHelper {
static func nextState(
service: LightWalletService,
downloader: CompactBlockDownloading,
config: Configuration,
rustBackend: ZcashRustBackendWelding.Type,
queue: DispatchQueue?,
result: @escaping (Result<FigureNextBatchOperation.NextState, Error>) -> Void
) {
let dispatchQueue = queue ?? DispatchQueue.global(qos: .userInitiated)
dispatchQueue.async {
do {
let r = try self.nextState(service: service,
downloader: downloader,
config: config,
rustBackend: rustBackend)
let r = try self.nextState(
service: service,
downloader: downloader,
config: config,
rustBackend: rustBackend)
result(.success(r))
} catch {
result(.failure(error))
@ -1311,28 +1363,34 @@ extension CompactBlockProcessor {
}
}
static func nextState(service: LightWalletService,
downloader: CompactBlockDownloading,
config: Configuration,
rustBackend: ZcashRustBackendWelding.Type) throws -> FigureNextBatchOperation.NextState {
static func nextState(
service: LightWalletService,
downloader: CompactBlockDownloading,
config: Configuration,
rustBackend: ZcashRustBackendWelding.Type
) throws -> FigureNextBatchOperation.NextState {
let info = try service.getInfo()
try CompactBlockProcessor.validateServerInfo(info, saplingActivation: config.saplingActivation, localNetwork: config.network, rustBackend: rustBackend)
// get latest block height
let latestDownloadedBlockHeight: BlockHeight = max(config.walletBirthday,try downloader.lastDownloadedBlockHeight())
let latestDownloadedBlockHeight: BlockHeight = max(config.walletBirthday, try downloader.lastDownloadedBlockHeight())
let latestBlockheight = try service.latestBlockHeight()
if latestDownloadedBlockHeight < latestBlockheight {
return .processNewBlocks(range: CompactBlockProcessor.nextBatchBlockRange(latestHeight: latestBlockheight, latestDownloadedHeight: latestDownloadedBlockHeight, walletBirthday: config.walletBirthday))
return .processNewBlocks(
range: CompactBlockProcessor.nextBatchBlockRange(
latestHeight: latestBlockheight,
latestDownloadedHeight: latestDownloadedBlockHeight,
walletBirthday: config.walletBirthday
)
)
} else if latestBlockheight == latestDownloadedBlockHeight {
return .finishProcessing(height: latestBlockheight)
}
return .wait(latestHeight: latestBlockheight, latestDownloadHeight: latestBlockheight)
}
}
}

View File

@ -169,10 +169,12 @@ class CompactBlockBatchScanningOperation: ZcashOperation {
}
let previousScannedHeight = lastScannedHeight
let scanStartTime = Date()
guard self.rustBackend.scanBlocks(dbCache: self.cacheDb,
dbData: self.dataDb,
limit: batchSize,
networkType: network) else {
guard self.rustBackend.scanBlocks(
dbCache: self.cacheDb,
dbData: self.dataDb,
limit: batchSize,
networkType: network
) else {
self.scanFailed(self.rustBackend.lastError() ?? ZcashOperationError.unknown)
return
}
@ -184,12 +186,18 @@ class CompactBlockBatchScanningOperation: ZcashOperation {
if scannedNewBlocks {
let progress = BlockProgress(startHeight: scanStartHeight, targetHeight: targetScanHeight, progressHeight: lastScannedHeight)
progressDelegate?.progressUpdated(.scan(progress))
NotificationCenter.default.post(SDKMetrics.progressReportNotification(progress: progress, start: scanStartTime, end: scanFinishTime, task: .scanBlocks))
NotificationCenter.default.post(
SDKMetrics.progressReportNotification(
progress: progress,
start: scanStartTime,
end: scanFinishTime,
task: .scanBlocks
)
)
// swiftlint:disable line_length
LoggerProxy.debug("Scanned \(lastScannedHeight - previousScannedHeight) blocks in \(scanFinishTime.timeIntervalSinceReferenceDate - scanStartTime.timeIntervalSinceReferenceDate) seconds")
}
} while !self.isCancelled && scannedNewBlocks && lastScannedHeight < targetScanHeight
}
} catch {
scanFailed(error)

View File

@ -51,8 +51,8 @@ class ZcashOperation: Operation {
self.cancel()
}
if let e = error {
self.error = e
if let error = error {
self.error = error
}
LoggerProxy.debug("\(self) failed")
@ -61,9 +61,8 @@ class ZcashOperation: Operation {
}
self.handlerDispatchQueue.async { [weak self] in
let e = error ?? (self?.error ?? ZcashOperationError.unknown)
errorHandler(e)
let error = error ?? (self?.error ?? ZcashOperationError.unknown)
errorHandler(error)
}
}
}

View File

@ -4,7 +4,7 @@
//
// Created by Francisco Gindre on 7/28/21.
//
// swiftlint:disable function_body_length line_length cyclomatic_complexity
import Foundation
extension WalletBirthday {

View File

@ -4,7 +4,7 @@
//
// Created by Francisco Gindre on 7/28/21.
//
// swiftlint:disable all
import Foundation
extension WalletBirthday {

View File

@ -67,146 +67,142 @@ public class ZcashSDK {
/**
The number of zatoshi that equal 1 ZEC.
*/
public static var ZATOSHI_PER_ZEC: BlockHeight = 100_000_000
public static var zatoshiPerZEC: BlockHeight = 100_000_000
/**
The theoretical maximum number of blocks in a reorg, due to other bottlenecks in the protocol design.
*/
public static var MAX_REORG_SIZE = 100
public static var maxReorgSize = 100
/**
The amount of blocks ahead of the current height where new transactions are set to expire. This value is controlled
by the rust backend but it is helpful to know what it is set to and should be kept in sync.
*/
public static var EXPIRY_OFFSET = 20
public static var expiryOffset = 20
//
// Defaults
//
/**
Default size of batches of blocks to request from the compact block service.
*/
public static var DEFAULT_BATCH_SIZE = 100
public static var DefaultBatchSize = 100
/**
Default amount of time, in in seconds, to poll for new blocks. Typically, this should be about half the average
block time.
*/
public static var DEFAULT_POLL_INTERVAL: TimeInterval = 20
public static var defaultPollInterval: TimeInterval = 20
/**
Default attempts at retrying.
*/
public static var DEFAULT_RETRIES: Int = 5
public static var defaultRetries: Int = 5
/**
The default maximum amount of time to wait during retry backoff intervals. Failed loops will never wait longer than
this before retyring.
*/
public static var DEFAULT_MAX_BACKOFF_INTERVAL: TimeInterval = 600
public static var defaultMaxBackOffInterval: TimeInterval = 600
/**
Default number of blocks to rewind when a chain reorg is detected. This should be large enough to recover from the
reorg but smaller than the theoretical max reorg size of 100.
*/
public static var DEFAULT_REWIND_DISTANCE: Int = 10
public static var defaultRewindDistance: Int = 10
/**
The number of blocks to allow before considering our data to be stale. This usually helps with what to do when
returning from the background and is exposed via the Synchronizer's isStale function.
*/
public static var DEFAULT_STALE_TOLERANCE: Int = 10
public static var defaultStaleTolerance: Int = 10
/**
Default Name for LibRustZcash data.db
*/
public static var DEFAULT_DATA_DB_NAME = "data.db"
public static var defaultDataDbName = "data.db"
/**
Default Name for Compact Block caches db
*/
public static var DEFAULT_CACHES_DB_NAME = "caches.db"
public static var defaultCacheDbName = "caches.db"
/**
Default name for pending transactions db
*/
public static var DEFAULT_PENDING_DB_NAME = "pending.db"
public static var defaultPendingDbName = "pending.db"
/**
File name for the sapling spend params
*/
public static var SPEND_PARAM_FILE_NAME = "sapling-spend.params"
public static var spendParamFilename = "sapling-spend.params"
/**
File name for the sapling output params
*/
public static var OUTPUT_PARAM_FILE_NAME = "sapling-output.params"
public static var outputParamFilename = "sapling-output.params"
/**
The Url that is used by default in zcashd.
We'll want to make this externally configurable, rather than baking it into the SDK but
this will do for now, since we're using a cloudfront URL that already redirects.
*/
public static var CLOUD_PARAM_DIR_URL = "https://z.cash/downloads/"
public static var cloudParameterURL = "https://z.cash/downloads/"
}
public protocol NetworkConstants {
/**
The height of the first sapling block. When it comes to shielded transactions, we do not need to consider any blocks
prior to this height, at all.
*/
static var SAPLING_ACTIVATION_HEIGHT: BlockHeight { get }
static var saplingActivationHeight: BlockHeight { get }
/**
Default Name for LibRustZcash data.db
*/
static var DEFAULT_DATA_DB_NAME: String { get }
static var defaultDataDbName: String { get }
/**
Default Name for Compact Block caches db
*/
static var DEFAULT_CACHES_DB_NAME: String { get }
static var defaultCacheDbName: String { get }
/**
Default name for pending transactions db
*/
static var DEFAULT_PENDING_DB_NAME: String { get }
static var DEFAULT_DB_NAME_PREFIX: String { get }
static var defaultPendingDbName: String { get }
static var defaultDbNamePrefix: String { get }
/**
fixed height where the SDK considers that the ZIP-321 was deployed. This is a workaround
for librustzcash not figuring out the tx fee from the tx itself.
*/
static var FEE_CHANGE_HEIGHT: BlockHeight { get }
static var feeChangeHeight: BlockHeight { get }
static func defaultFee(for height: BlockHeight) -> Int64
}
public extension NetworkConstants {
static func defaultFee(for height: BlockHeight = BlockHeight.max) -> Int64 {
guard height >= FEE_CHANGE_HEIGHT else { return 10_000 }
guard height >= feeChangeHeight else { return 10_000 }
return 1_000
}
}
public class ZcashSDKMainnetConstants: NetworkConstants {
private init() {}
/**
The height of the first sapling block. When it comes to shielded transactions, we do not need to consider any blocks
prior to this height, at all.
*/
public static var SAPLING_ACTIVATION_HEIGHT: BlockHeight = 419_200
public static var saplingActivationHeight: BlockHeight = 419_200
/**
Default Name for LibRustZcash data.db
*/
public static var DEFAULT_DATA_DB_NAME = "data.db"
public static var defaultDataDbName = "data.db"
/**
Default Name for Compact Block caches db
*/
public static var DEFAULT_CACHES_DB_NAME = "caches.db"
public static var defaultCacheDbName = "caches.db"
/**
Default name for pending transactions db
*/
public static var DEFAULT_PENDING_DB_NAME = "pending.db"
public static var defaultPendingDbName = "pending.db"
public static var DEFAULT_DB_NAME_PREFIX = "ZcashSdk_mainnet_"
public static var defaultDbNamePrefix = "ZcashSdk_mainnet_"
public static var FEE_CHANGE_HEIGHT: BlockHeight = 1_077_550
public static var feeChangeHeight: BlockHeight = 1_077_550
}
public class ZcashSDKTestnetConstants: NetworkConstants {
@ -216,26 +212,25 @@ public class ZcashSDKTestnetConstants: NetworkConstants {
The height of the first sapling block. When it comes to shielded transactions, we do not need to consider any blocks
prior to this height, at all.
*/
public static var SAPLING_ACTIVATION_HEIGHT: BlockHeight = 280_000
public static var saplingActivationHeight: BlockHeight = 280_000
/**
Default Name for LibRustZcash data.db
*/
public static var DEFAULT_DATA_DB_NAME = "data.db"
public static var defaultDataDbName = "data.db"
/**
Default Name for Compact Block caches db
*/
public static var DEFAULT_CACHES_DB_NAME = "caches.db"
public static var defaultCacheDbName = "caches.db"
/**
Default name for pending transactions db
*/
public static var DEFAULT_PENDING_DB_NAME = "pending.db"
public static var defaultPendingDbName = "pending.db"
public static var DEFAULT_DB_NAME_PREFIX = "ZcashSdk_testnet_"
public static var defaultDbNamePrefix = "ZcashSdk_testnet_"
/**
Estimated height where wallets are supposed to change the fee
*/
public static var FEE_CHANGE_HEIGHT: BlockHeight = 1_028_500
public static var feeChangeHeight: BlockHeight = 1_028_500
}

View File

@ -118,40 +118,39 @@ class PendingTransactionSQLDAO: PendingTransactionRepository {
}
func createrTableIfNeeded() throws {
let statement = table.create(ifNotExists: true) { t in
t.column(TableColumns.id, primaryKey: .autoincrement)
t.column(TableColumns.toAddress)
t.column(TableColumns.accountIndex)
t.column(TableColumns.minedHeight)
t.column(TableColumns.expiryHeight)
t.column(TableColumns.cancelled)
t.column(TableColumns.encodeAttempts, defaultValue: 0)
t.column(TableColumns.errorMessage)
t.column(TableColumns.errorCode)
t.column(TableColumns.submitAttempts, defaultValue: 0)
t.column(TableColumns.createTime)
t.column(TableColumns.rawTransactionId)
t.column(TableColumns.value)
t.column(TableColumns.raw)
t.column(TableColumns.memo)
let statement = table.create(ifNotExists: true) { createdTable in
createdTable.column(TableColumns.id, primaryKey: .autoincrement)
createdTable.column(TableColumns.toAddress)
createdTable.column(TableColumns.accountIndex)
createdTable.column(TableColumns.minedHeight)
createdTable.column(TableColumns.expiryHeight)
createdTable.column(TableColumns.cancelled)
createdTable.column(TableColumns.encodeAttempts, defaultValue: 0)
createdTable.column(TableColumns.errorMessage)
createdTable.column(TableColumns.errorCode)
createdTable.column(TableColumns.submitAttempts, defaultValue: 0)
createdTable.column(TableColumns.createTime)
createdTable.column(TableColumns.rawTransactionId)
createdTable.column(TableColumns.value)
createdTable.column(TableColumns.raw)
createdTable.column(TableColumns.memo)
}
try dbProvider.connection().run(statement)
}
func create(_ transaction: PendingTransactionEntity) throws -> Int {
let pendingTx = transaction as? PendingTransaction ?? PendingTransaction.from(entity: transaction)
let tx = transaction as? PendingTransaction ?? PendingTransaction.from(entity: transaction)
return try Int(dbProvider.connection().run(table.insert(tx)))
return try Int(dbProvider.connection().run(table.insert(pendingTx)))
}
func update(_ transaction: PendingTransactionEntity) throws {
let tx = transaction as? PendingTransaction ?? PendingTransaction.from(entity: transaction)
guard let id = tx.id else {
let pendingTx = transaction as? PendingTransaction ?? PendingTransaction.from(entity: transaction)
guard let id = pendingTx.id else {
throw StorageError.malformedEntity(fields: ["id"])
}
let updatedRows = try dbProvider.connection().run(table.filter(TableColumns.id == id).update(tx))
let updatedRows = try dbProvider.connection().run(table.filter(TableColumns.id == id).update(pendingTx))
if updatedRows == 0 {
LoggerProxy.error("attempted to update pending transactions but no rows were updated")
}
@ -166,17 +165,16 @@ class PendingTransactionSQLDAO: PendingTransactionRepository {
} catch {
throw StorageError.updateFailed
}
}
func cancel(_ transaction: PendingTransactionEntity) throws {
var tx = transaction as? PendingTransaction ?? PendingTransaction.from(entity: transaction)
tx.cancelled = 1
guard let id = tx.id else {
var pendingTx = transaction as? PendingTransaction ?? PendingTransaction.from(entity: transaction)
pendingTx.cancelled = 1
guard let txId = pendingTx.id else {
throw StorageError.malformedEntity(fields: ["id"])
}
try dbProvider.connection().run(table.filter(TableColumns.id == id).update(tx))
try dbProvider.connection().run(table.filter(TableColumns.id == txId).update(pendingTx))
}
func find(by id: Int) throws -> PendingTransactionEntity? {
@ -184,8 +182,8 @@ class PendingTransactionSQLDAO: PendingTransactionRepository {
return nil
}
do {
let tx: PendingTransaction = try row.decode()
return tx
let pendingTx: PendingTransaction = try row.decode()
return pendingTx
} catch {
throw StorageError.operationFailed
}

View File

@ -60,14 +60,13 @@ extension UnspentTransactionOutputEntity {
}
import SQLite
class UnspentTransactionOutputSQLDAO: UnspentTransactionOutputRepository {
func store(utxos: [UnspentTransactionOutputEntity]) throws {
do {
let db = try dbProvider.connection()
try dbProvider.connection().transaction {
for utxo in utxos.map({ (u) -> UTXO in
u as? UTXO ?? u.asUTXO()
for utxo in utxos.map({ (mappedUTXO) -> UTXO in
mappedUTXO as? UTXO ?? mappedUTXO.asUTXO()
}) {
try db.run(table.insert(utxo))
}
@ -153,7 +152,7 @@ class UnspentTransactionOutputSQLDAO: UnspentTransactionOutputRepository {
let verified = try dbProvider.connection().scalar(
table.select(TableColumns.valueZat.sum)
.filter(TableColumns.address == address)
.filter(TableColumns.height <= latestHeight - ZcashSDK.DEFAULT_STALE_TOLERANCE)) ?? 0
.filter(TableColumns.height <= latestHeight - ZcashSDK.defaultStaleTolerance)) ?? 0
let total = try dbProvider.connection().scalar(
table.select(TableColumns.valueZat.sum)
.filter(TableColumns.address == address)) ?? 0

View File

@ -114,10 +114,10 @@ class AccountSQDAO: AccountRepository {
}
func update(_ account: AccountEntity) throws {
guard let a = account as? Account else {
guard let acc = account as? Account else {
throw StorageError.updateFailed
}
let updatedRows = try dbProvider.connection().run(table.filter(TableColums.account == a.account).update(a))
let updatedRows = try dbProvider.connection().run(table.filter(TableColums.account == acc.account).update(acc))
if updatedRows == 0 {
LoggerProxy.error("attempted to update pending transactions but no rows were updated")
throw StorageError.updateFailed
@ -126,17 +126,16 @@ class AccountSQDAO: AccountRepository {
}
class CachingAccountDao: AccountRepository {
var dao: AccountRepository
lazy var cache: [Int: AccountEntity] = {
var c = [Int : AccountEntity]()
var accountCache = [Int: AccountEntity]()
guard let all = try? dao.getAll() else {
return c
return accountCache
}
for a in all {
c[a.account] = a
for acc in all {
accountCache[acc.account] = acc
}
return c
return accountCache
}()
init(dao: AccountRepository) {
@ -149,20 +148,20 @@ class CachingAccountDao: AccountRepository {
}
let all = try dao.getAll()
for a in all {
cache[a.account] = a
for acc in all {
cache[acc.account] = acc
}
return all
}
func findBy(account: Int) throws -> AccountEntity? {
if let a = cache[account] {
return a
if let acc = cache[account] {
return acc
}
let a = try dao.findBy(account: account)
cache[account] = a
return a
let acc = try dao.findBy(account: account)
cache[account] = acc
return acc
}
func findBy(address: String) throws -> AccountEntity? {

View File

@ -153,7 +153,7 @@ public extension PendingTransactionEntity {
return false
}
return abs(currentHeight - minedHeight) >= ZcashSDK.DEFAULT_STALE_TOLERANCE
return abs(currentHeight - minedHeight) >= ZcashSDK.defaultStaleTolerance
}
}
@ -162,7 +162,15 @@ public extension PendingTransactionEntity {
TransactionEntity representation of this PendingTransactionEntity transaction
*/
var transactionEntity: TransactionEntity {
Transaction(id: self.id ?? -1, transactionId: self.rawTransactionId ?? Data(), created: Date(timeIntervalSince1970: self.createTime).description, transactionIndex: -1, expiryHeight: self.expiryHeight, minedHeight: self.minedHeight, raw: self.raw)
Transaction(
id: self.id ?? -1,
transactionId: self.rawTransactionId ?? Data(),
created: Date(timeIntervalSince1970: self.createTime).description,
transactionIndex: -1,
expiryHeight: self.expiryHeight,
minedHeight: self.minedHeight,
raw: self.raw
)
}
}
@ -171,6 +179,14 @@ public extension ConfirmedTransactionEntity {
TransactionEntity representation of this ConfirmedTransactionEntity transaction
*/
var transactionEntity: TransactionEntity {
Transaction(id: self.id ?? -1, transactionId: self.rawTransactionId ?? Data(), created: Date(timeIntervalSince1970: self.blockTimeInSeconds).description, transactionIndex: self.transactionIndex, expiryHeight: self.expiryHeight, minedHeight: self.minedHeight, raw: self.raw)
Transaction(
id: self.id ?? -1,
transactionId: self.rawTransactionId ?? Data(),
created: Date(timeIntervalSince1970: self.blockTimeInSeconds).description,
transactionIndex: self.transactionIndex,
expiryHeight: self.expiryHeight,
minedHeight: self.minedHeight,
raw: self.raw
)
}
}

View File

@ -59,11 +59,11 @@ public extension TransactionEntity {
func anchor(network: ZcashNetwork) -> BlockHeight? {
if let minedHeight = self.minedHeight, minedHeight != -1 {
return max(minedHeight - ZcashSDK.DEFAULT_STALE_TOLERANCE, network.constants.SAPLING_ACTIVATION_HEIGHT)
return max(minedHeight - ZcashSDK.defaultStaleTolerance, network.constants.saplingActivationHeight)
}
if let expiryHeight = self.expiryHeight, expiryHeight != -1 {
return max(expiryHeight - ZcashSDK.EXPIRY_OFFSET - ZcashSDK.DEFAULT_STALE_TOLERANCE, network.constants.SAPLING_ACTIVATION_HEIGHT)
return max(expiryHeight - ZcashSDK.expiryOffset - ZcashSDK.defaultStaleTolerance, network.constants.saplingActivationHeight)
}
return nil

View File

@ -10,11 +10,13 @@ import Foundation
extension String {
func toTxIdString() -> String {
var id = ""
self.reversed().pairs.map {
$0.reversed()
}.forEach { (reversed) in
id.append(String(reversed))
}
self.reversed().pairs
.map {
$0.reversed()
}
.forEach { (reversed) in
id.append(String(reversed))
}
return id
}
}
@ -23,8 +25,8 @@ extension Collection {
var pairs: [SubSequence] {
var startIndex = self.startIndex
let count = self.count
let n = count / 2 + count % 2
return (0..<n).map { _ in
let halving = count / 2 + count % 2
return (0..<halving).map { _ in
let endIndex = index(startIndex, offsetBy: 2, limitedBy: self.endIndex) ?? self.endIndex
defer { startIndex = endIndex }
return self[startIndex..<endIndex]

View File

@ -195,7 +195,14 @@ public class Initializer {
}
do {
try rustBackend.initBlocksTable(dbData: dataDbURL, height: Int32(walletBirthday.height), hash: walletBirthday.hash, time: walletBirthday.time, saplingTree: walletBirthday.tree, networkType: network.networkType)
try rustBackend.initBlocksTable(
dbData: dataDbURL,
height: Int32(walletBirthday.height),
hash: walletBirthday.hash,
time: walletBirthday.time,
saplingTree: walletBirthday.tree,
networkType: network.networkType
)
} catch RustWeldingError.dataDbNotEmpty {
// this is fine
} catch {
@ -212,14 +219,16 @@ public class Initializer {
}
} catch RustWeldingError.dataDbNotEmpty {
// this is fine
}catch {
} catch {
throw rustBackend.lastError() ?? InitializerError.accountInitFailed
}
let migrationManager = MigrationManager(cacheDbConnection: SimpleConnectionProvider(path: cacheDbURL.path),
dataDbConnection: SimpleConnectionProvider(path: dataDbURL.path),
pendingDbConnection: SimpleConnectionProvider(path: pendingDbURL.path),
networkType: self.network.networkType)
let migrationManager = MigrationManager(
cacheDbConnection: SimpleConnectionProvider(path: cacheDbURL.path),
dataDbConnection: SimpleConnectionProvider(path: dataDbURL.path),
pendingDbConnection: SimpleConnectionProvider(path: pendingDbURL.path),
networkType: self.network.networkType
)
try migrationManager.performMigration(uvks: viewingKeys)
}
@ -257,7 +266,7 @@ public class Initializer {
checks if the provided address is a transparent zAddress
*/
public func isValidTransparentAddress(_ address: String) -> Bool {
(try? rustBackend.isValidTransparentAddress(address,networkType: network.networkType)) ?? false
(try? rustBackend.isValidTransparentAddress(address, networkType: network.networkType)) ?? false
}
func isSpendParameterPresent() -> Bool {
@ -268,7 +277,7 @@ public class Initializer {
FileManager.default.isReadableFile(atPath: self.outputParamsURL.path)
}
func downloadParametersIfNeeded(result: @escaping (Result<Bool,Error>) -> Void) {
func downloadParametersIfNeeded(result: @escaping (Result<Bool, Error>) -> Void) {
let spendParameterPresent = isSpendParameterPresent()
let outputParameterPresent = isOutputParameterPresent()
@ -283,17 +292,17 @@ public class Initializer {
if !outputParameterPresent {
SaplingParameterDownloader.downloadOutputParameter(outputURL) { outputResult in
switch outputResult {
case .failure(let e):
result(.failure(e))
case .failure(let error):
result(.failure(error))
case .success:
guard !spendParameterPresent else {
result(.success(false))
return
}
SaplingParameterDownloader.downloadSpendParameter(spendURL) { (spendResult) in
SaplingParameterDownloader.downloadSpendParameter(spendURL) { spendResult in
switch spendResult {
case .failure(let e):
result(.failure(e))
case .failure(let error):
result(.failure(error))
case .success:
result(.success(false))
}
@ -301,10 +310,10 @@ public class Initializer {
}
}
} else if !spendParameterPresent {
SaplingParameterDownloader.downloadSpendParameter(spendURL) { (spendResult) in
SaplingParameterDownloader.downloadSpendParameter(spendURL) { spendResult in
switch spendResult {
case .failure(let e):
result(.failure(e))
case .failure(let error):
result(.failure(error))
case .success:
result(.success(false))
}
@ -314,17 +323,21 @@ public class Initializer {
}
class CompactBlockProcessorBuilder {
static func buildProcessor(configuration: CompactBlockProcessor.Configuration,
service: LightWalletService,
storage: CompactBlockStorage,
transactionRepository: TransactionRepository,
accountRepository: AccountRepository,
backend: ZcashRustBackendWelding.Type) -> CompactBlockProcessor {
return CompactBlockProcessor(service: service,
storage: storage,
backend: backend,
config: configuration,
repository: transactionRepository,
accountRepository: accountRepository)
static func buildProcessor(
configuration: CompactBlockProcessor.Configuration,
service: LightWalletService,
storage: CompactBlockStorage,
transactionRepository: TransactionRepository,
accountRepository: AccountRepository,
backend: ZcashRustBackendWelding.Type
) -> CompactBlockProcessor {
return CompactBlockProcessor(
service: service,
storage: storage,
backend: backend,
config: configuration,
repository: transactionRepository,
accountRepository: accountRepository
)
}
}

View File

@ -29,9 +29,9 @@ public struct DefaultResourceProvider: ResourceProvider {
let constants = network.constants
do {
let url = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
return url.appendingPathComponent(constants.DEFAULT_DATA_DB_NAME)
return url.appendingPathComponent(constants.defaultDataDbName)
} catch {
return URL(fileURLWithPath: "file://\(constants.DEFAULT_DATA_DB_NAME)")
return URL(fileURLWithPath: "file://\(constants.defaultDataDbName)")
}
}
@ -40,9 +40,9 @@ public struct DefaultResourceProvider: ResourceProvider {
let constants = network.constants
do {
let path = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
return path.appendingPathComponent(constants.DEFAULT_CACHES_DB_NAME)
return path.appendingPathComponent(constants.defaultCacheDbName)
} catch {
return URL(fileURLWithPath: "file://\(constants.DEFAULT_CACHES_DB_NAME)")
return URL(fileURLWithPath: "file://\(constants.defaultCacheDbName)")
}
}

View File

@ -5,11 +5,10 @@
// Created by Jack Grigg on 5/8/19.
// Copyright © 2019 Electric Coin Company. All rights reserved.
//
// swiftlint:disable type_body_length
import Foundation
class ZcashRustBackend: ZcashRustBackendWelding {
static func lastError() -> RustWeldingError? {
guard let message = getLastError() else { return nil }
zcashlc_clear_last_error()
@ -127,15 +126,15 @@ class ZcashRustBackend: ZcashRustBackendWelding {
let extpubCStr = [CChar](String(uvk.extpub).utf8CString)
let extpubPtr = UnsafeMutablePointer<CChar>.allocate(capacity: extpubCStr.count)
extpubPtr.initialize(from:extpubCStr, count: extpubCStr.count)
extpubPtr.initialize(from: extpubCStr, count: extpubCStr.count)
ffiUvks.append(FFIUnifiedViewingKey(extfvk: extfvkPtr, extpub: extpubPtr))
}
var result = false
ffiUvks.withContiguousMutableStorageIfAvailable { p in
ffiUvks.withContiguousMutableStorageIfAvailable { pointer in
let slice = UnsafeMutablePointer<FFIUVKBoxedSlice>.allocate(capacity: 1)
slice.initialize(to: FFIUVKBoxedSlice(ptr: p.baseAddress, len: UInt(p.count)))
slice.initialize(to: FFIUVKBoxedSlice(ptr: pointer.baseAddress, len: UInt(pointer.count)))
result = zcashlc_init_accounts_table_with_keys(dbData.0, dbData.1, slice, networkType.networkId)
slice.deinitialize(count: 1)
@ -149,10 +148,16 @@ class ZcashRustBackend: ZcashRustBackendWelding {
}
return result
}
static func initBlocksTable(dbData: URL, height: Int32, hash: String, time: UInt32, saplingTree: String, networkType: NetworkType) throws {
// swiftlint:disable function_parameter_count
static func initBlocksTable(
dbData: URL,
height: Int32,
hash: String,
time: UInt32,
saplingTree: String,
networkType: NetworkType
) throws {
let dbData = dbData.osStr()
guard !hash.containsCStringNullBytesBeforeStringEnding() else {
@ -163,7 +168,15 @@ class ZcashRustBackend: ZcashRustBackendWelding {
throw RustWeldingError.malformedStringInput
}
guard zcashlc_init_blocks_table(dbData.0, dbData.1, height, [CChar](hash.utf8CString), time, [CChar](saplingTree.utf8CString), networkType.networkId) != 0 else {
guard zcashlc_init_blocks_table(
dbData.0,
dbData.1,
height,
[CChar](hash.utf8CString),
time,
[CChar](saplingTree.utf8CString),
networkType.networkId
) != 0 else {
if let error = lastError() {
throw error
}
@ -315,55 +328,70 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return zcashlc_scan_blocks(dbCache.0, dbCache.1, dbData.0, dbData.1, limit, networkType.networkId) != 0
}
static func decryptAndStoreTransaction(dbData: URL, tx: [UInt8], minedHeight: Int32, networkType: NetworkType) -> Bool {
static func decryptAndStoreTransaction(dbData: URL, txBytes: [UInt8], minedHeight: Int32, networkType: NetworkType) -> Bool {
let dbData = dbData.osStr()
return zcashlc_decrypt_and_store_transaction(dbData.0, dbData.1, tx, UInt(tx.count), UInt32(minedHeight), networkType.networkId) != 0
return zcashlc_decrypt_and_store_transaction(dbData.0, dbData.1, txBytes, UInt(txBytes.count), UInt32(minedHeight), networkType.networkId) != 0
}
// swiftlint:disable function_parameter_count
static func createToAddress(dbData: URL, account: Int32, extsk: String, to: String, value: Int64, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64 {
let dbData = dbData.osStr()
let memoBytes = memo ?? ""
return zcashlc_create_to_address(dbData.0,
dbData.1,
account,
[CChar](extsk.utf8CString),
[CChar](to.utf8CString),
value,
[CChar](memoBytes.utf8CString),
spendParamsPath,
UInt(spendParamsPath.lengthOfBytes(using: .utf8)),
outputParamsPath,
UInt(outputParamsPath.lengthOfBytes(using: .utf8)),
networkType.networkId)
return zcashlc_create_to_address(
dbData.0,
dbData.1,
account,
[CChar](extsk.utf8CString),
[CChar](to.utf8CString),
value,
[CChar](memoBytes.utf8CString),
spendParamsPath,
UInt(spendParamsPath.lengthOfBytes(using: .utf8)),
outputParamsPath,
UInt(outputParamsPath.lengthOfBytes(using: .utf8)),
networkType.networkId
)
}
static func shieldFunds(dbCache: URL, dbData: URL, account: Int32, tsk: String, extsk: String, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64 {
static func shieldFunds(
dbCache: URL,
dbData: URL,
account: Int32,
tsk: String,
extsk: String,
memo: String?,
spendParamsPath: String,
outputParamsPath: String,
networkType: NetworkType
) -> Int64 {
let dbData = dbData.osStr()
let memoBytes = memo ?? ""
return zcashlc_shield_funds(dbData.0,
dbData.1,
account,
[CChar](tsk.utf8CString),
[CChar](extsk.utf8CString),
[CChar](memoBytes.utf8CString),
spendParamsPath,
UInt(spendParamsPath.lengthOfBytes(using: .utf8)),
outputParamsPath,
UInt(outputParamsPath.lengthOfBytes(using: .utf8)),
networkType.networkId)
return zcashlc_shield_funds(
dbData.0,
dbData.1,
account,
[CChar](tsk.utf8CString),
[CChar](extsk.utf8CString),
[CChar](memoBytes.utf8CString),
spendParamsPath,
UInt(spendParamsPath.lengthOfBytes(using: .utf8)),
outputParamsPath,
UInt(outputParamsPath.lengthOfBytes(using: .utf8)),
networkType.networkId
)
}
static func deriveExtendedFullViewingKey(_ spendingKey: String, networkType: NetworkType) throws -> String? {
guard !spendingKey.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput
}
guard let extsk = zcashlc_derive_extended_full_viewing_key([CChar](spendingKey.utf8CString),
networkType.networkId) else {
guard let extsk = zcashlc_derive_extended_full_viewing_key(
[CChar](spendingKey.utf8CString),
networkType.networkId
) else {
if let error = lastError() {
throw error
}
@ -377,7 +405,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
}
static func deriveExtendedFullViewingKeys(seed: [UInt8], accounts: Int32, networkType: NetworkType) throws -> [String]? {
var capacity = UInt(0);
var capacity = UInt(0)
guard let extsksCStr = zcashlc_derive_extended_full_viewing_keys(seed, UInt(seed.count), accounts, &capacity, networkType.networkId) else {
if let error = lastError() {
throw error
@ -385,16 +413,17 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return nil
}
let extsks = UnsafeBufferPointer(start: extsksCStr, count: Int(accounts)).compactMap({ (cStr) -> String? in
let extsks = UnsafeBufferPointer(start: extsksCStr, count: Int(accounts)).compactMap { (cStr) -> String? in
guard let str = cStr else { return nil }
return String(cString: str)
})
}
zcashlc_vec_string_free(extsksCStr, UInt(accounts), capacity)
return extsks
}
static func deriveExtendedSpendingKeys(seed: [UInt8], accounts: Int32, networkType: NetworkType) throws -> [String]? {
var capacity = UInt(0);
var capacity = UInt(0)
guard let extsksCStr = zcashlc_derive_extended_spending_keys(seed, UInt(seed.count), accounts, &capacity, networkType.networkId) else {
if let error = lastError() {
throw error
@ -402,31 +431,35 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return nil
}
let extsks = UnsafeBufferPointer(start: extsksCStr, count: Int(accounts)).compactMap({ (cStr) -> String? in
let extsks = UnsafeBufferPointer(start: extsksCStr, count: Int(accounts)).compactMap { cStr -> String? in
guard let str = cStr else { return nil }
return String(cString: str)
})
}
zcashlc_vec_string_free(extsksCStr, UInt(accounts), capacity)
return extsks
}
static func deriveUnifiedViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int, networkType: NetworkType) throws -> [UnifiedViewingKey] {
guard let uvks_struct = zcashlc_derive_unified_viewing_keys_from_seed(seed, UInt(seed.count), Int32(numberOfAccounts), networkType.networkId) else {
guard let uvksStruct = zcashlc_derive_unified_viewing_keys_from_seed(
seed,
UInt(seed.count),
Int32(numberOfAccounts),
networkType.networkId
) else {
if let error = lastError() {
throw error
}
throw RustWeldingError.unableToDeriveKeys
}
let uvks_size = uvks_struct.pointee.len
guard let uvks_array_pointer = uvks_struct.pointee.ptr, uvks_size > 0 else {
let uvksSize = uvksStruct.pointee.len
guard let uvksArrayPointer = uvksStruct.pointee.ptr, uvksSize > 0 else {
throw RustWeldingError.unableToDeriveKeys
}
var uvks = [UnifiedViewingKey]()
for i: Int in 0 ..< Int(uvks_size) {
let itemPointer = uvks_array_pointer.advanced(by: i)
for i: Int in 0 ..< Int(uvksSize) {
let itemPointer = uvksArrayPointer.advanced(by: i)
guard let extfvk = String(validatingUTF8: itemPointer.pointee.extfvk) else {
throw RustWeldingError.unableToDeriveKeys
@ -439,12 +472,16 @@ class ZcashRustBackend: ZcashRustBackendWelding {
uvks.append(UVK(extfvk: extfvk, extpub: extpub))
}
zcashlc_free_uvk_array(uvks_struct)
zcashlc_free_uvk_array(uvksStruct)
return uvks
}
static func deriveShieldedAddressFromSeed(seed: [UInt8], accountIndex: Int32, networkType: NetworkType) throws -> String? {
static func deriveShieldedAddressFromSeed(
seed: [UInt8],
accountIndex: Int32,
networkType: NetworkType
) throws -> String? {
guard let zaddrCStr = zcashlc_derive_shielded_address_from_seed(seed, UInt(seed.count), accountIndex, networkType.networkId) else {
if let error = lastError() {
throw error
@ -458,12 +495,17 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return zAddr
}
static func deriveShieldedAddressFromViewingKey(_ extfvk: String, networkType: NetworkType) throws -> String? {
static func deriveShieldedAddressFromViewingKey(
_ extfvk: String,
networkType: NetworkType
) throws -> String? {
guard !extfvk.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput
}
guard let zaddrCStr = zcashlc_derive_shielded_address_from_viewing_key([CChar](extfvk.utf8CString), networkType.networkId) else {
guard let zaddrCStr = zcashlc_derive_shielded_address_from_viewing_key(
[CChar](extfvk.utf8CString),
networkType.networkId
) else {
if let error = lastError() {
throw error
}
@ -476,7 +518,12 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return zAddr
}
static func deriveTransparentAddressFromSeed(seed: [UInt8], account: Int, index: Int, networkType: NetworkType) throws -> String? {
static func deriveTransparentAddressFromSeed(
seed: [UInt8],
account: Int,
index: Int,
networkType: NetworkType
) throws -> String? {
guard let tAddrCStr = zcashlc_derive_transparent_address_from_seed(seed, UInt(seed.count), Int32(account), Int32(index), networkType.networkId) else {
if let error = lastError() {
@ -490,7 +537,12 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return tAddr
}
static func deriveTransparentPrivateKeyFromSeed(seed: [UInt8], account: Int, index: Int, networkType: NetworkType) throws -> String? {
static func deriveTransparentPrivateKeyFromSeed(
seed: [UInt8],
account: Int,
index: Int,
networkType: NetworkType
) throws -> String? {
guard let skCStr = zcashlc_derive_transparent_private_key_from_seed(seed, UInt(seed.count), Int32(account), Int32(index), networkType.networkId) else {
if let error = lastError() {
throw error
@ -502,12 +554,18 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return sk
}
static func derivedTransparentAddressFromPublicKey(_ pubkey: String, networkType: NetworkType) throws -> String {
static func derivedTransparentAddressFromPublicKey(
_ pubkey: String,
networkType: NetworkType
) throws -> String {
guard !pubkey.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput
}
guard let tAddrCStr = zcashlc_derive_transparent_address_from_public_key([CChar](pubkey.utf8CString), networkType.networkId), let tAddr = String(validatingUTF8: tAddrCStr) else {
guard let tAddrCStr = zcashlc_derive_transparent_address_from_public_key(
[CChar](pubkey.utf8CString),
networkType.networkId),
let tAddr = String(validatingUTF8: tAddrCStr) else {
if let error = lastError() {
throw error
}
@ -541,7 +599,6 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return branchId
}
}
private struct UVK: UnifiedViewingKey {
@ -551,26 +608,21 @@ private struct UVK: UnifiedViewingKey {
private extension ZcashRustBackend {
static func throwDataDbError(_ error: RustWeldingError) -> Error {
if case RustWeldingError.genericError(let message) = error, message.contains("is not empty") {
return RustWeldingError.dataDbNotEmpty
}
return RustWeldingError.dataDbInitFailed(message: error.localizedDescription)
}
}
private extension URL {
func osStr() -> (String, UInt) {
let path = self.absoluteString
return (path, UInt(path.lengthOfBytes(using: .utf8)))
}
}
extension String {
/**
Checks whether this string contains null bytes before it's real ending
*/

View File

@ -81,7 +81,15 @@ public protocol ZcashRustBackendWelding {
- time: in milliseconds from reference
- saplingTree: hash of the sapling tree
*/
static func initBlocksTable(dbData: URL, height: Int32, hash: String, time: UInt32, saplingTree: String, networkType: NetworkType) throws
// swiftlint:disable function_parameter_count
static func initBlocksTable(
dbData: URL,
height: Int32,
hash: String,
time: UInt32,
saplingTree: String,
networkType: NetworkType
) throws
/**
gets the address from data db from the given account
@ -228,7 +236,10 @@ public protocol ZcashRustBackendWelding {
- minedHeight: height on which this transaction was mined. this is used to fetch the consensus branch ID.
returns false if fails to decrypt.
*/
static func decryptAndStoreTransaction(dbData: URL, tx: [UInt8], minedHeight: Int32, networkType: NetworkType) -> Bool
static func decryptAndStoreTransaction(dbData: URL,
txBytes: [UInt8],
minedHeight: Int32,
networkType: NetworkType) -> Bool
/**
Creates a transaction to the given address from the given account
@ -242,7 +253,18 @@ public protocol ZcashRustBackendWelding {
- spendParamsPath: path escaped String for the filesystem locations where the spend parameters are located
- outputParamsPath: path escaped String for the filesystem locations where the output parameters are located
*/
static func createToAddress(dbData: URL, account: Int32, extsk: String, to: String, value: Int64, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64
// swiftlint:disable function_parameter_count
static func createToAddress(
dbData: URL,
account: Int32,
extsk: String,
to: String,
value: Int64,
memo: String?,
spendParamsPath: String,
outputParamsPath: String,
networkType: NetworkType
) -> Int64
/**
Creates a transaction to shield all found UTXOs in cache db.
@ -256,7 +278,18 @@ public protocol ZcashRustBackendWelding {
- spendParamsPath: path escaped String for the filesystem locations where the spend parameters are located
- outputParamsPath: path escaped String for the filesystem locations where the output parameters are located
*/
static func shieldFunds(dbCache: URL, dbData: URL, account: Int32, tsk: String, extsk: String, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64
// swiftlint:disable function_parameter_count
static func shieldFunds(
dbCache: URL,
dbData: URL,
account: Int32,
tsk: String,
extsk: String,
memo: String?,
spendParamsPath: String,
outputParamsPath: String,
networkType: NetworkType
) -> Int64
/**
Derives a full viewing key from a seed

View File

@ -164,18 +164,31 @@ public class LightWalletGRPCService {
}
extension LightWalletGRPCService: LightWalletService {
@discardableResult public func blockStream(startHeight: BlockHeight, endHeight: BlockHeight, result: @escaping (Result<GRPCResult, LightWalletServiceError>) -> Void, handler: @escaping (ZcashCompactBlock) -> Void, progress: @escaping (BlockProgressReporting) -> Void) -> CancellableCall {
let future = compactTxStreamer.getBlockRange(BlockRange(startHeight: startHeight, endHeight: endHeight), callOptions: Self.callOptions(timeLimit: self.streamingCallTimeout), handler: { compactBlock in
handler(ZcashCompactBlock(compactBlock: compactBlock))
progress(BlockProgress(startHeight: startHeight, targetHeight: endHeight, progressHeight: BlockHeight(compactBlock.height)))
@discardableResult public func blockStream(
startHeight: BlockHeight,
endHeight: BlockHeight,
result: @escaping (Result<GRPCResult, LightWalletServiceError>) -> Void,
handler: @escaping (ZcashCompactBlock) -> Void,
progress: @escaping (BlockProgressReporting) -> Void
) -> CancellableCall {
let future = compactTxStreamer.getBlockRange(
BlockRange(
startHeight: startHeight,
endHeight: endHeight),
callOptions: Self.callOptions(timeLimit: self.streamingCallTimeout),
handler: { compactBlock in
handler(ZcashCompactBlock(compactBlock: compactBlock))
progress(BlockProgress(
startHeight: startHeight,
targetHeight: endHeight,
progressHeight: BlockHeight(compactBlock.height)
)
)
}
)
future.status.whenComplete { r in
switch r {
future.status.whenComplete { completionResult in
switch completionResult {
case .success(let status):
switch status.code {
case .ok:
@ -195,8 +208,8 @@ extension LightWalletGRPCService: LightWalletService {
}
public func getInfo(result: @escaping (Result<LightWalletdInfo, LightWalletServiceError>) -> Void) {
compactTxStreamer.getLightdInfo(Empty()).response.whenComplete { r in
switch r {
compactTxStreamer.getLightdInfo(Empty()).response.whenComplete { completionResult in
switch completionResult {
case .success(let info):
result(.success(info))
case .failure(let error):
@ -223,19 +236,17 @@ extension LightWalletGRPCService: LightWalletService {
}
public func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
var txFilter = TxFilter()
txFilter.hash = txId
compactTxStreamer.getTransaction(txFilter).response.whenComplete({ response in
compactTxStreamer.getTransaction(txFilter).response.whenComplete { response in
switch response {
case .failure(let error):
result(.failure(error.mapToServiceError()))
case .success(let rawTx):
result(.success(TransactionBuilder.createTransactionEntity(txId: txId, rawTransaction: rawTx)))
}
})
}
}
public func submit(spendTransaction: Data, result: @escaping (Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
@ -243,12 +254,12 @@ extension LightWalletGRPCService: LightWalletService {
let tx = try RawTransaction(serializedData: spendTransaction)
let response = self.compactTxStreamer.sendTransaction(tx).response
response.whenComplete { (responseResult) in
response.whenComplete { responseResult in
switch responseResult {
case .failure(let e):
result(.failure(LightWalletServiceError.sentFailed(error: e)))
case .success(let s):
result(.success(s))
case .failure(let error):
result(.failure(LightWalletServiceError.sentFailed(error: error)))
case .success(let success):
result(.success(success))
}
}
} catch {
@ -257,8 +268,7 @@ extension LightWalletGRPCService: LightWalletService {
}
public func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
let rawTx = RawTransaction.with { (raw) in
let rawTx = RawTransaction.with { raw in
raw.data = spendTransaction
}
do {
@ -273,14 +283,15 @@ extension LightWalletGRPCService: LightWalletService {
let response = compactTxStreamer.getBlockRange(range.blockRange(), handler: {
blocks.append($0)
})
}
)
let status = try response.status.wait()
switch status.code {
case .ok:
case .ok:
return blocks.asZcashCompactBlocks()
default:
default:
throw LightWalletServiceError.mapCode(status)
}
}
@ -299,13 +310,10 @@ extension LightWalletGRPCService: LightWalletService {
response.whenFailureBlocking(onto: queue) { error in
result(.failure(error.mapToServiceError()))
}
}
public func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void) {
queue.async { [weak self] in
guard let self = self else { return }
var blocks = [CompactBlock]()
@ -321,7 +329,6 @@ extension LightWalletGRPCService: LightWalletService {
default:
result(.failure(.mapCode(status)))
}
} catch {
result(.failure(error.mapToServiceError()))
}
@ -329,7 +336,6 @@ extension LightWalletGRPCService: LightWalletService {
}
public func latestBlockHeight() throws -> BlockHeight {
guard let height = try? latestBlock().compactBlockHeight() else {
throw LightWalletServiceError.invalidBlock
}
@ -337,20 +343,21 @@ extension LightWalletGRPCService: LightWalletService {
}
public func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
let arg = GetAddressUtxosArg.with { (utxoArgs) in
let arg = GetAddressUtxosArg.with { utxoArgs in
utxoArgs.addresses = [tAddress]
utxoArgs.startHeight = UInt64(height)
}
do {
return try self.compactTxStreamer.getAddressUtxos(arg).response.wait().addressUtxos.map { reply in
UTXO(id: nil,
address: tAddress,
prevoutTxId: reply.txid,
prevoutIndex: Int(reply.index),
script: reply.script,
valueZat: Int(reply.valueZat),
height: Int(reply.height),
spentInTx: nil
UTXO(
id: nil,
address: tAddress,
prevoutTxId: reply.txid,
prevoutIndex: Int(reply.index),
script: reply.script,
valueZat: Int(reply.valueZat),
height: Int(reply.height),
spentInTx: nil
)
}
} catch {
@ -361,21 +368,22 @@ extension LightWalletGRPCService: LightWalletService {
public func fetchUTXOs(for tAddress: String, height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) {
queue.async { [weak self] in
guard let self = self else { return }
let arg = GetAddressUtxosArg.with { (utxoArgs) in
let arg = GetAddressUtxosArg.with { utxoArgs in
utxoArgs.addresses = [tAddress]
utxoArgs.startHeight = UInt64(height)
}
var utxos = [UnspentTransactionOutputEntity]()
let response = self.compactTxStreamer.getAddressUtxosStream(arg) { (reply) in
let response = self.compactTxStreamer.getAddressUtxosStream(arg) { reply in
utxos.append(
UTXO(id: nil,
address: tAddress,
prevoutTxId: reply.txid,
prevoutIndex: Int(reply.index),
script: reply.script,
valueZat: Int(reply.valueZat),
height: Int(reply.height),
spentInTx: nil
UTXO(
id: nil,
address: tAddress,
prevoutTxId: reply.txid,
prevoutIndex: Int(reply.index),
script: reply.script,
valueZat: Int(reply.valueZat),
height: Int(reply.height),
spentInTx: nil
)
)
}
@ -395,37 +403,37 @@ extension LightWalletGRPCService: LightWalletService {
}
public func fetchUTXOs(for tAddresses: [String], height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
guard tAddresses.count > 0 else {
guard !tAddresses.isEmpty else {
return [] // FIXME: throw a real error
}
var utxos = [UnspentTransactionOutputEntity]()
let arg = GetAddressUtxosArg.with { (utxoArgs) in
let arg = GetAddressUtxosArg.with { utxoArgs in
utxoArgs.addresses = tAddresses
utxoArgs.startHeight = UInt64(height)
}
utxos.append(contentsOf:
try self.compactTxStreamer.getAddressUtxos(arg).response.wait().addressUtxos.map({ reply in
UTXO(id: nil,
address: reply.address,
prevoutTxId: reply.txid,
prevoutIndex: Int(reply.index),
script: reply.script,
valueZat: Int(reply.valueZat),
height: Int(reply.height),
spentInTx: nil)
})
utxos.append(
contentsOf:
try self.compactTxStreamer.getAddressUtxos(arg).response.wait().addressUtxos.map { reply in
UTXO(
id: nil,
address: reply.address,
prevoutTxId: reply.txid,
prevoutIndex: Int(reply.index),
script: reply.script,
valueZat: Int(reply.valueZat),
height: Int(reply.height),
spentInTx: nil
)
}
)
return utxos
}
public func fetchUTXOs(for tAddresses: [String], height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) {
guard tAddresses.count > 0 else {
guard !tAddresses.isEmpty else {
return result(.success([])) // FIXME: throw a real error
}
@ -439,16 +447,20 @@ extension LightWalletGRPCService: LightWalletService {
do {
let response = try self.compactTxStreamer.getAddressUtxosStream(args) { reply in
utxos.append(
UTXO(id: nil,
address: reply.address,
prevoutTxId: reply.txid,
prevoutIndex: Int(reply.index),
script: reply.script,
valueZat: Int(reply.valueZat),
height: Int(reply.height),
spentInTx: nil)
UTXO(
id: nil,
address: reply.address,
prevoutTxId: reply.txid,
prevoutIndex: Int(reply.index),
script: reply.script,
valueZat: Int(reply.valueZat),
height: Int(reply.height),
spentInTx: nil
)
)
}.status.wait()
}
.status
.wait()
switch response.code {
case .ok:
result(.success(utxos))
@ -476,7 +488,6 @@ extension Error {
extension LightWalletServiceError {
static func mapCode(_ status: GRPCStatus) -> LightWalletServiceError {
switch status.code {
case .ok:
return LightWalletServiceError.unknown
case .cancelled:
@ -499,8 +510,9 @@ class ConnectionStatusManager: ConnectivityStateDelegate {
name: .blockProcessorConnectivityStateChanged,
object: self,
userInfo: [
CompactBlockProcessorNotificationKey.currentConnectivityStatus : newState,
CompactBlockProcessorNotificationKey.previousConnectivityStatus : oldState
])
CompactBlockProcessorNotificationKey.currentConnectivityStatus: newState,
CompactBlockProcessorNotificationKey.previousConnectivityStatus: oldState
]
)
}
}

View File

@ -32,6 +32,8 @@ public protocol BlockProgressReporting {
}
extension LightWalletServiceError: Equatable {
// swiftlint:disable cyclomatic_complexity
// swiftlint:disable identifier_name
public static func == (lhs: Self, rhs: Self) -> Bool {
switch lhs {
case .generalError(let m):
@ -74,21 +76,21 @@ extension LightWalletServiceError: Equatable {
return false
}
case .criticalError:
switch rhs {
switch rhs {
case .criticalError:
return true
default:
return false
}
case .userCancelled:
switch rhs {
switch rhs {
case .userCancelled:
return true
default:
return false
}
case .unknown:
switch rhs {
switch rhs {
case .unknown:
return true
default:
@ -121,7 +123,7 @@ public protocol LightWalletService {
- Parameter result: a result containing the height or an Error
*/
func latestBlockHeight(result: @escaping (Result<BlockHeight,LightWalletServiceError>) -> Void)
func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void)
/**
Return the latest block height known to the service.
@ -150,13 +152,19 @@ public protocol LightWalletService {
*/
func blockRange(_ range: CompactBlockRange) throws -> [ZcashCompactBlock]
@discardableResult func blockStream(startHeight: BlockHeight, endHeight: BlockHeight, result: @escaping (Result<GRPCResult, LightWalletServiceError>) -> Void, handler: @escaping (ZcashCompactBlock) -> Void, progress: @escaping (BlockProgressReporting) -> Void) -> CancellableCall
@discardableResult func blockStream(
startHeight: BlockHeight,
endHeight: BlockHeight,
result: @escaping (Result<GRPCResult, LightWalletServiceError>) -> Void,
handler: @escaping (ZcashCompactBlock) -> Void,
progress: @escaping (BlockProgressReporting) -> Void
) -> CancellableCall
/**
Submits a raw transaction over lightwalletd. Non-Blocking
- Parameter spendTransaction: data representing the transaction to be sent
- Parameter result: escaping closure that takes a result containing either LightWalletServiceResponse or LightWalletServiceError
*/
func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse,LightWalletServiceError>) -> Void)
func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void)
/**
Submits a raw transaction over lightwalletd. Blocking
@ -183,7 +191,7 @@ public protocol LightWalletService {
- Throws: LightWalletServiceError
- Returns: LightWalletServiceResponse
*/
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity,LightWalletServiceError>) -> Void)
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void)
func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity]

View File

@ -11,6 +11,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
// swiftlint:disable all
import Foundation
import SwiftProtobuf

View File

@ -11,6 +11,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
// swiftlint:disable all
import Foundation
import SwiftProtobuf

View File

@ -51,22 +51,46 @@ class PersistentTransactionManager: OutboundTransactionManager {
guard let self = self else { return }
let derivationTool = DerivationTool(networkType: self.network)
guard let vk = try? derivationTool.deriveViewingKey(spendingKey: spendingKey),
let zAddr = try? derivationTool.deriveShieldedAddress(viewingKey: vk) else {
result(.failure(TransactionManagerError.shieldingEncodingFailed(tx: pendingTransaction, reason: "There was an error Deriving your keys")))
return
guard let viewingKey = try? derivationTool.deriveViewingKey(spendingKey: spendingKey),
let zAddr = try? derivationTool.deriveShieldedAddress(viewingKey: viewingKey) else {
result(
.failure(
TransactionManagerError.shieldingEncodingFailed(
tx: pendingTransaction,
reason: "There was an error Deriving your keys")
)
)
return
}
guard pendingTransaction.toAddress == zAddr else {
result(.failure(TransactionManagerError.shieldingEncodingFailed(tx: pendingTransaction, reason: "the recipient address does not match your derived shielded address. Shielding transactions addresses must match the ones derived from your keys. This is a serious error. We are not letting you encode this shielding transaction because it can lead to loss of funds")))
result(
.failure(
TransactionManagerError.shieldingEncodingFailed(
tx: pendingTransaction,
reason: """
the recipient address does not match your
derived shielded address. Shielding transactions
addresses must match the ones derived from your keys.
This is a serious error. We are not letting you encode
this shielding transaction because it can lead to loss
of funds
"""
)
)
)
return
}
do {
let encodedTransaction = try self.encoder.createShieldingTransaction(spendingKey: spendingKey, tSecretKey: tsk, memo: pendingTransaction.memo?.asZcashTransactionMemo(), from: pendingTransaction.accountIndex)
let encodedTransaction = try self.encoder.createShieldingTransaction(
spendingKey: spendingKey,
tSecretKey: tsk,
memo: pendingTransaction.memo?.asZcashTransactionMemo(),
from: pendingTransaction.accountIndex)
let transaction = try self.encoder.expandEncodedTransaction(encodedTransaction)
var pending = pendingTransaction
pending.encodeAttempts = pending.encodeAttempts + 1
pending.encodeAttempts += 1
pending.raw = encodedTransaction.raw
pending.rawTransactionId = encodedTransaction.transactionId
pending.expiryHeight = transaction.expiryHeight ?? BlockHeight.empty()
@ -85,16 +109,23 @@ class PersistentTransactionManager: OutboundTransactionManager {
}
}
func encode(spendingKey: String, pendingTransaction: PendingTransactionEntity, result: @escaping (Result<PendingTransactionEntity, Error>) -> Void) {
func encode(spendingKey: String,
pendingTransaction: PendingTransactionEntity,
result: @escaping (Result<PendingTransactionEntity, Error>) -> Void) {
queue.async { [weak self] in
guard let self = self else { return }
do {
let encodedTransaction = try self.encoder.createTransaction(spendingKey: spendingKey, zatoshi: pendingTransaction.value, to: pendingTransaction.toAddress, memo: pendingTransaction.memo?.asZcashTransactionMemo(), from: pendingTransaction.accountIndex)
let encodedTransaction = try self.encoder.createTransaction(
spendingKey: spendingKey,
zatoshi: pendingTransaction.value,
to: pendingTransaction.toAddress,
memo: pendingTransaction.memo?.asZcashTransactionMemo(),
from: pendingTransaction.accountIndex)
let transaction = try self.encoder.expandEncodedTransaction(encodedTransaction)
var pending = pendingTransaction
pending.encodeAttempts = pending.encodeAttempts + 1
pending.encodeAttempts += 1
pending.raw = encodedTransaction.raw
pending.rawTransactionId = encodedTransaction.transactionId
pending.expiryHeight = transaction.expiryHeight ?? BlockHeight.empty()
@ -120,8 +151,8 @@ class PersistentTransactionManager: OutboundTransactionManager {
}
}
func submit(pendingTransaction: PendingTransactionEntity, result: @escaping (Result<PendingTransactionEntity, Error>) -> Void) {
func submit(pendingTransaction: PendingTransactionEntity,
result: @escaping (Result<PendingTransactionEntity, Error>) -> Void) {
guard let txId = pendingTransaction.id else {
result(.failure(TransactionManagerError.notPending(tx: pendingTransaction)))// this transaction is not stored
return
@ -149,13 +180,13 @@ class PersistentTransactionManager: OutboundTransactionManager {
}
let response = try self.service.submit(spendTransaction: raw)
let tx = try self.update(transaction: storedTx, on: response)
let transaction = try self.update(transaction: storedTx, on: response)
guard response.errorCode >= 0 else {
result(.failure(TransactionManagerError.submitFailed(tx: tx, errorCode: Int(response.errorCode))))
result(.failure(TransactionManagerError.submitFailed(tx: transaction, errorCode: Int(response.errorCode))))
return
}
result(.success(tx))
result(.success(transaction))
} catch {
try? self.updateOnFailure(tx: pendingTransaction, error: error)
result(.failure(error))
@ -191,8 +222,8 @@ class PersistentTransactionManager: OutboundTransactionManager {
return
}
try affectedTxs.map { (tx) -> PendingTransactionEntity in
var updatedTx = tx
try affectedTxs.map { (transaction) -> PendingTransactionEntity in
var updatedTx = transaction
updatedTx.minedHeight = -1
return updatedTx
} .forEach({ try self.repository.update($0) })
@ -227,13 +258,13 @@ class PersistentTransactionManager: OutboundTransactionManager {
}
private func update(transaction: PendingTransactionEntity, on sendResponse: LightWalletServiceResponse) throws -> PendingTransactionEntity {
var tx = transaction
tx.submitAttempts = tx.submitAttempts + 1
var pendingTx = transaction
pendingTx.submitAttempts += 1
let error = sendResponse.errorCode < 0
tx.errorCode = error ? Int(sendResponse.errorCode) : nil
tx.errorMessage = error ? sendResponse.errorMessage : nil
try repository.update(tx)
return tx
pendingTx.errorCode = error ? Int(sendResponse.errorCode) : nil
pendingTx.errorMessage = error ? sendResponse.errorMessage : nil
try repository.update(pendingTx)
return pendingTx
}
func delete(pendingTransaction: PendingTransactionEntity) throws {
@ -243,18 +274,20 @@ class PersistentTransactionManager: OutboundTransactionManager {
throw TransactionManagerError.notPending(tx: pendingTransaction)
}
}
}
class OutboundTransactionManagerBuilder {
enum OutboundTransactionManagerBuilder {
static func build(initializer: Initializer) throws -> OutboundTransactionManager {
return PersistentTransactionManager(encoder: TransactionEncoderbuilder.build(initializer: initializer), service: initializer.lightWalletService, repository: try PendingTransactionRepositoryBuilder.build(initializer: initializer), networkType: initializer.network.networkType)
PersistentTransactionManager(
encoder: TransactionEncoderbuilder.build(initializer: initializer),
service: initializer.lightWalletService,
repository: try PendingTransactionRepositoryBuilder.build(initializer: initializer),
networkType: initializer.network.networkType
)
}
}
class PendingTransactionRepositoryBuilder {
enum PendingTransactionRepositoryBuilder {
static func build(initializer: Initializer) throws -> PendingTransactionRepository {
let dao = PendingTransactionSQLDAO(dbProvider: SimpleConnectionProvider(path: initializer.pendingDbURL.path, readonly: false))
try dao.createrTableIfNeeded()
@ -262,7 +295,7 @@ class PendingTransactionRepositoryBuilder {
}
}
class TransactionEncoderbuilder {
enum TransactionEncoderbuilder {
static func build(initializer: Initializer) -> TransactionEncoder {
WalletTransactionEncoder(initializer: initializer)
}

View File

@ -7,11 +7,11 @@
import Foundation
typealias TransactionEncoderResultBlock = (_ result: Result<EncodedTransaction,Error>) -> Void
typealias TransactionEncoderResultBlock = (_ result: Result<EncodedTransaction, Error>) -> Void
public enum TransactionEncoderError: Error {
case notFound(transactionId: Int)
case NotEncoded(transactionId: Int)
case notEncoded(transactionId: Int)
case missingParams
case spendingKeyWrongNetwork
case couldNotExpand(txId: Data)
@ -34,7 +34,13 @@ protocol TransactionEncoder {
- Throws: a TransactionEncoderError
*/
func createTransaction(spendingKey: String, zatoshi: Int, to: String, memo: String?, from accountIndex: Int) throws -> EncodedTransaction
func createTransaction(
spendingKey: String,
zatoshi: Int,
to: String,
memo: String?,
from accountIndex: Int
) throws -> EncodedTransaction
/**
Creates a transaction, throwing an exception whenever things are missing. When the provided wallet implementation
@ -50,7 +56,14 @@ protocol TransactionEncoder {
- Parameter accountIndex: index of the account that will be used to send the funds
- Parameter result: a non escaping closure that receives a Result containing either an EncodedTransaction or a TransactionEncoderError
*/
func createTransaction(spendingKey: String, zatoshi: Int, to: String, memo: String?, from accountIndex: Int, result: @escaping TransactionEncoderResultBlock)
func createTransaction(
spendingKey: String,
zatoshi: Int,
to: String,
memo: String?,
from accountIndex: Int,
result: @escaping TransactionEncoderResultBlock
)
/**
Creates a transaction that will attempt to shield transparent funds that are present on the cacheDB .throwing an exception whenever things are missing. When the provided wallet implementation
@ -66,7 +79,12 @@ protocol TransactionEncoder {
- Throws: a TransactionEncoderError
*/
func createShieldingTransaction(spendingKey: String, tSecretKey: String, memo: String?, from accountIndex: Int) throws -> EncodedTransaction
func createShieldingTransaction(
spendingKey: String,
tSecretKey: String,
memo: String?,
from accountIndex: Int
) throws -> EncodedTransaction
/**
Creates a transaction that will attempt to shield transparent funds that are present on the cacheDB .throwing an exception whenever things are missing. When the provided wallet implementation
@ -83,7 +101,13 @@ protocol TransactionEncoder {
- Returns: a TransactionEncoderResultBlock
*/
func createShieldingTransaction(spendingKey: String, tSecretKey: String, memo: String?, from accountIndex: Int, result: @escaping TransactionEncoderResultBlock)
func createShieldingTransaction(
spendingKey: String,
tSecretKey: String,
memo: String?,
from accountIndex: Int,
result: @escaping TransactionEncoderResultBlock
)
/**
Fetch the Transaction Entity from the encoded representation

View File

@ -161,9 +161,9 @@ class WalletTransactionEncoder: TransactionEncoder {
- Throws: a TransactionEncoderError
*/
func expandEncodedTransaction(_ encodedTransaction: EncodedTransaction) throws -> TransactionEntity {
guard let t = try? repository.findBy(rawId: encodedTransaction.transactionId) else {
guard let transaction = try? repository.findBy(rawId: encodedTransaction.transactionId) else {
throw TransactionEncoderError.couldNotExpand(txId: encodedTransaction.transactionId)
}
return t
return transaction
}
}

View File

@ -98,9 +98,9 @@ public extension Notification.Name {
/**
Synchronizer implementation for UIKit and iOS 12+
*/
// swiftlint:disable type_body_length
public class SDKSynchronizer: Synchronizer {
public struct NotificationKeys {
public enum NotificationKeys {
public static let progress = "SDKSynchronizer.progress"
public static let blockHeight = "SDKSynchronizer.blockHeight"
public static let blockDate = "SDKSynchronizer.blockDate"
@ -135,22 +135,23 @@ public class SDKSynchronizer: Synchronizer {
- Parameter initializer: a wallet Initializer object
*/
public convenience init(initializer: Initializer) throws {
try self.init(status: .unprepared,
initializer: initializer,
transactionManager: try OutboundTransactionManagerBuilder.build(initializer: initializer),
transactionRepository: initializer.transactionRepository,
utxoRepository: try UTXORepositoryBuilder.build(initializer: initializer),
blockProcessor: CompactBlockProcessor(initializer: initializer))
try self.init(
status: .unprepared,
initializer: initializer,
transactionManager: try OutboundTransactionManagerBuilder.build(initializer: initializer),
transactionRepository: initializer.transactionRepository,
utxoRepository: try UTXORepositoryBuilder.build(initializer: initializer),
blockProcessor: CompactBlockProcessor(initializer: initializer))
}
init(status: SyncStatus,
initializer: Initializer,
transactionManager: OutboundTransactionManager,
transactionRepository: TransactionRepository,
utxoRepository: UnspentTransactionOutputRepository,
blockProcessor: CompactBlockProcessor) throws {
init(
status: SyncStatus,
initializer: Initializer,
transactionManager: OutboundTransactionManager,
transactionRepository: TransactionRepository,
utxoRepository: UnspentTransactionOutputRepository,
blockProcessor: CompactBlockProcessor
) throws {
self.connectionState = .idle
self.status = status
self.initializer = initializer
@ -183,7 +184,6 @@ public class SDKSynchronizer: Synchronizer {
- Throws: CompactBlockProcessorError when failures occur
*/
public func start(retry: Bool = false) throws {
switch status {
case .unprepared:
throw SynchronizerError.notPrepared
@ -195,7 +195,7 @@ public class SDKSynchronizer: Synchronizer {
// assert(false,"warning: synchronizer started when already started") // TODO: remove this assertion sometime in the near future
LoggerProxy.warn("warning: synchronizer started when already started")
return
case .stopped, .synced,.disconnected, .error:
case .stopped, .synced, .disconnected, .error:
do {
try blockProcessor.start(retry: retry)
} catch {
@ -208,7 +208,6 @@ public class SDKSynchronizer: Synchronizer {
Stops the synchronizer
*/
public func stop() {
guard status != .stopped, status != .disconnected else {
LoggerProxy.info("attempted to stop when status was: \(status)")
return
@ -221,74 +220,103 @@ public class SDKSynchronizer: Synchronizer {
private func subscribeToProcessorNotifications(_ processor: CompactBlockProcessor) {
let center = NotificationCenter.default
center.addObserver(self,
selector: #selector(processorUpdated(_:)),
name: Notification.Name.blockProcessorUpdated,
object: processor)
center.addObserver(
self,
selector: #selector(processorUpdated(_:)),
name: Notification.Name.blockProcessorUpdated,
object: processor
)
center.addObserver(self,
selector: #selector(processorStartedDownloading(_:)),
name: Notification.Name.blockProcessorStartedDownloading,
object: processor)
center.addObserver(
self,
selector: #selector(processorStartedDownloading(_:)),
name: Notification.Name.blockProcessorStartedDownloading,
object: processor
)
center.addObserver(self,
selector: #selector(processorStartedValidating(_:)),
name: Notification.Name.blockProcessorStartedValidating,
object: processor)
center.addObserver(
self,
selector: #selector(processorStartedValidating(_:)),
name: Notification.Name.blockProcessorStartedValidating,
object: processor
)
center.addObserver(self,
selector: #selector(processorStartedScanning(_:)),
name: Notification.Name.blockProcessorStartedScanning,
object: processor)
center.addObserver(
self,
selector: #selector(processorStartedScanning(_:)),
name: Notification.Name.blockProcessorStartedScanning,
object: processor
)
center.addObserver(self,
selector: #selector(processorStartedEnhancing(_:)),
name: Notification.Name.blockProcessorStartedEnhancing,
object: processor)
center.addObserver(
self,
selector: #selector(processorStartedEnhancing(_:)),
name: Notification.Name.blockProcessorStartedEnhancing,
object: processor
)
center.addObserver(self,
selector: #selector(processorStartedFetching(_:)),
name: Notification.Name.blockProcessorStartedFetching,
object: processor)
center.addObserver(
self,
selector: #selector(processorStartedFetching(_:)),
name: Notification.Name.blockProcessorStartedFetching,
object: processor
)
center.addObserver(self,
selector: #selector(processorStopped(_:)),
name: Notification.Name.blockProcessorStopped,
object: processor)
center.addObserver(
self,
selector: #selector(processorStopped(_:)),
name: Notification.Name.blockProcessorStopped,
object: processor
)
center.addObserver(self, selector: #selector(processorFailed(_:)),
name: Notification.Name.blockProcessorFailed,
object: processor)
center.addObserver(
self,
selector: #selector(processorFailed(_:)),
name: Notification.Name.blockProcessorFailed,
object: processor
)
center.addObserver(self,
selector: #selector(processorIdle(_:)),
name: Notification.Name.blockProcessorIdle,
object: processor)
center.addObserver(
self,
selector: #selector(processorIdle(_:)),
name: Notification.Name.blockProcessorIdle,
object: processor
)
center.addObserver(self,
selector: #selector(processorFinished(_:)),
name: Notification.Name.blockProcessorFinished,
object: processor)
center.addObserver(
self,
selector: #selector(processorFinished(_:)),
name: Notification.Name.blockProcessorFinished,
object: processor
)
center.addObserver(self,
selector: #selector(processorTransitionUnknown(_:)),
name: Notification.Name.blockProcessorUnknownTransition,
object: processor)
center.addObserver(
self,
selector: #selector(processorTransitionUnknown(_:)),
name: Notification.Name.blockProcessorUnknownTransition,
object: processor
)
center.addObserver(self,
selector: #selector(reorgDetected(_:)),
name: Notification.Name.blockProcessorHandledReOrg,
object: processor)
center.addObserver(
self,
selector: #selector(reorgDetected(_:)),
name: Notification.Name.blockProcessorHandledReOrg,
object: processor
)
center.addObserver(self,
selector: #selector(transactionsFound(_:)),
name: Notification.Name.blockProcessorFoundTransactions,
object: processor)
center.addObserver(
self,
selector: #selector(transactionsFound(_:)),
name: Notification.Name.blockProcessorFoundTransactions,
object: processor
)
center.addObserver(self,
selector: #selector(connectivityStateChanged(_:)),
name: Notification.Name.blockProcessorConnectivityStateChanged,
object: nil)
center.addObserver(
self,
selector: #selector(connectivityStateChanged(_:)),
name: Notification.Name.blockProcessorConnectivityStateChanged,
object: nil
)
}
// MARK: Block Processor notifications
@ -304,9 +332,10 @@ public class SDKSynchronizer: Synchronizer {
name: .synchronizerConnectionStateChanged,
object: self,
userInfo: [
NotificationKeys.previousConnectionState : ConnectionState(previous),
NotificationKeys.currentConnectionState : currentState
])
NotificationKeys.previousConnectionState: ConnectionState(previous),
NotificationKeys.currentConnectionState: currentState
]
)
DispatchQueue.main.async { [weak self] in
self?.connectionState = currentState
@ -318,7 +347,13 @@ public class SDKSynchronizer: Synchronizer {
let foundTransactions = userInfo[CompactBlockProcessorNotificationKey.foundTransactions] as? [ConfirmedTransactionEntity] else {
return
}
NotificationCenter.default.post(name: .synchronizerFoundTransactions, object: self, userInfo: [ NotificationKeys.foundTransactions : foundTransactions])
NotificationCenter.default.post(
name: .synchronizerFoundTransactions,
object: self,
userInfo: [
NotificationKeys.foundTransactions: foundTransactions
]
)
}
@objc func reorgDetected(_ notification: Notification) {
@ -388,14 +423,16 @@ public class SDKSynchronizer: Synchronizer {
}
@objc func processorFailed(_ notification: Notification) {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
if let error = notification.userInfo?[CompactBlockProcessorNotificationKey.error] as? Error {
self.notifyFailure(error)
self.status = .error(self.mapError(error))
} else {
self.notifyFailure(CompactBlockProcessorError.generalError(message: "This is strange. processorFailed Call received no error message"))
self.notifyFailure(
CompactBlockProcessorError.generalError(
message: "This is strange. processorFailed Call received no error message")
)
self.status = .error(SynchronizerError.generalError(message: "This is strange. processorFailed Call received no error message"))
}
}
@ -426,14 +463,27 @@ public class SDKSynchronizer: Synchronizer {
}
// MARK: Synchronizer methods
public func sendToAddress(spendingKey: String, zatoshi: Int64, toAddress: String, memo: String?, from accountIndex: Int, resultBlock: @escaping (Result<PendingTransactionEntity, Error>) -> Void) {
// swiftlint:disable type_body_length
public func sendToAddress(
spendingKey: String,
zatoshi: Int64,
toAddress: String,
memo: String?,
from accountIndex: Int,
resultBlock: @escaping (Result<PendingTransactionEntity, Error>
) -> Void) {
initializer.downloadParametersIfNeeded { (downloadResult) in
DispatchQueue.main.async { [weak self] in
switch downloadResult {
case .success:
self?.createToAddress(spendingKey: spendingKey, zatoshi: zatoshi, toAddress: toAddress, memo: memo, from: accountIndex, resultBlock: resultBlock)
self?.createToAddress(
spendingKey: spendingKey,
zatoshi: zatoshi,
toAddress: toAddress,
memo: memo,
from: accountIndex,
resultBlock: resultBlock
)
case .failure(let error):
resultBlock(.failure(SynchronizerError.parameterMissing(underlyingError: error)))
}
@ -441,8 +491,13 @@ public class SDKSynchronizer: Synchronizer {
}
}
public func shieldFunds(spendingKey: String, transparentSecretKey: String, memo: String?, from accountIndex: Int, resultBlock: @escaping (Result<PendingTransactionEntity, Error>) -> Void) {
public func shieldFunds(
spendingKey: String,
transparentSecretKey: String,
memo: String?,
from accountIndex: Int,
resultBlock: @escaping (Result<PendingTransactionEntity, Error>
) -> Void) {
// let's see if there are funds to shield
let derivationTool = DerivationTool(networkType: self.network.networkType)
@ -455,8 +510,8 @@ public class SDKSynchronizer: Synchronizer {
resultBlock(.failure(ShieldFundsError.insuficientTransparentFunds))
return
}
let vk = try derivationTool.deriveViewingKey(spendingKey: spendingKey)
let zAddr = try derivationTool.deriveShieldedAddress(viewingKey: vk)
let viewingKey = try derivationTool.deriveViewingKey(spendingKey: spendingKey)
let zAddr = try derivationTool.deriveShieldedAddress(viewingKey: viewingKey)
let shieldingSpend = try transactionManager.initSpend(zatoshi: Int(tBalance.verified), toAddress: zAddr, memo: memo, from: 0)
@ -564,7 +619,7 @@ public class SDKSynchronizer: Synchronizer {
return
}
initializer.lightWalletService.fetchUTXOs(for: address, height: network.constants.SAPLING_ACTIVATION_HEIGHT, result: { [weak self] r in
initializer.lightWalletService.fetchUTXOs(for: address, height: network.constants.saplingActivationHeight, result: { [weak self] r in
guard let self = self else { return }
switch r {
case .success(let utxos):
@ -720,7 +775,7 @@ public class SDKSynchronizer: Synchronizer {
let latestHeight = try transactionRepository.lastScannedHeight()
try transactionManager.allPendingTransactions()?.filter( {
$0.minedHeight > 0 && abs($0.minedHeight - latestHeight) >= ZcashSDK.DEFAULT_STALE_TOLERANCE }
$0.minedHeight > 0 && abs($0.minedHeight - latestHeight) >= ZcashSDK.defaultStaleTolerance }
).forEach( {
try transactionManager.delete(pendingTransaction: $0)
} )

View File

@ -45,8 +45,8 @@ public class SaplingParameterDownloader {
private static func downloadFileWithRequest(_ request: URLRequest, at destination: URL, result: @escaping (Result<URL,Error>) -> Void) {
let task = URLSession.shared.downloadTask(with: request) { (url, _, error) in
if let e = error {
result(.failure(Errors.failed(error: e)))
if let error = error {
result(.failure(Errors.failed(error: error)))
return
} else if let localUrl = url {
do {
@ -110,10 +110,10 @@ public class SaplingParameterDownloader {
}
public static var spendParamsURLString: String {
return ZcashSDK.CLOUD_PARAM_DIR_URL + ZcashSDK.SPEND_PARAM_FILE_NAME
return ZcashSDK.cloudParameterURL + ZcashSDK.spendParamFilename
}
public static var outputParamsURLString: String {
return ZcashSDK.CLOUD_PARAM_DIR_URL + ZcashSDK.OUTPUT_PARAM_FILE_NAME
return ZcashSDK.cloudParameterURL + ZcashSDK.outputParamFilename
}
}

View File

@ -28,14 +28,14 @@ class BlockBatchValidationTests: XCTestCase {
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.SAPLING_ACTIVATION_HEIGHT, network: network)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.saplingActivationHeight, network: network)
var info = LightdInfo()
info.blockHeight = 130000
info.branch = "d34db33f"
info.chainName = "main"
info.buildUser = "test user"
info.consensusBranchID = "d34db33f"
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
service.mockLightDInfo = info
let mockRust = MockRustBackend.self
@ -68,14 +68,14 @@ class BlockBatchValidationTests: XCTestCase {
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.SAPLING_ACTIVATION_HEIGHT, network: network)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.saplingActivationHeight, network: network)
var info = LightdInfo()
info.blockHeight = 130000
info.branch = "d34db33f"
info.chainName = "test"
info.buildUser = "test user"
info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
service.mockLightDInfo = info
let mockRust = MockRustBackend.self
@ -109,14 +109,14 @@ class BlockBatchValidationTests: XCTestCase {
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.SAPLING_ACTIVATION_HEIGHT, network: network)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.saplingActivationHeight, network: network)
var info = LightdInfo()
info.blockHeight = 130000
info.branch = "d34db33f"
info.chainName = "another"
info.buildUser = "test user"
info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
service.mockLightDInfo = info
let mockRust = MockRustBackend.self
@ -149,7 +149,7 @@ class BlockBatchValidationTests: XCTestCase {
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.SAPLING_ACTIVATION_HEIGHT, network: network)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.saplingActivationHeight, network: network)
var info = LightdInfo()
info.blockHeight = 130000
info.branch = "d34db33f"
@ -171,7 +171,7 @@ class BlockBatchValidationTests: XCTestCase {
operation.errorHandler = { error in
expectation.fulfill()
switch error {
case CompactBlockProcessorError.saplingActivationMismatch(expected: network.constants.SAPLING_ACTIVATION_HEIGHT, found: BlockHeight(info.saplingActivationHeight)):
case CompactBlockProcessorError.saplingActivationMismatch(expected: network.constants.saplingActivationHeight, found: BlockHeight(info.saplingActivationHeight)):
break
default:
XCTFail("Expected CompactBlockProcessorError.saplingActivationMismatch but found \(error)")
@ -193,14 +193,14 @@ class BlockBatchValidationTests: XCTestCase {
let expectedResult = FigureNextBatchOperation.NextState.wait(latestHeight: expectedLatestHeight, latestDownloadHeight: expectedLatestHeight)
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.SAPLING_ACTIVATION_HEIGHT, network: network)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.saplingActivationHeight, network: network)
var info = LightdInfo()
info.blockHeight = UInt64(expectedLatestHeight)
info.branch = "d34db33f"
info.chainName = "main"
info.buildUser = "test user"
info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
service.mockLightDInfo = info
let mockRust = MockRustBackend.self
@ -250,14 +250,14 @@ class BlockBatchValidationTests: XCTestCase {
let expectedResult = FigureNextBatchOperation.NextState.processNewBlocks(range: CompactBlockProcessor.nextBatchBlockRange(latestHeight: expectedLatestHeight, latestDownloadedHeight: expectedStoreLatestHeight, walletBirthday: walletBirthday))
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: walletBirthday, saplingActivation: network.constants.SAPLING_ACTIVATION_HEIGHT, network: network)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: walletBirthday, saplingActivation: network.constants.saplingActivationHeight, network: network)
var info = LightdInfo()
info.blockHeight = UInt64(expectedLatestHeight)
info.branch = "d34db33f"
info.chainName = "main"
info.buildUser = "test user"
info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
service.mockLightDInfo = info
let mockRust = MockRustBackend.self
@ -307,14 +307,14 @@ class BlockBatchValidationTests: XCTestCase {
let expectedResult = FigureNextBatchOperation.NextState.finishProcessing(height: expectedStoreLatestHeight)
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: walletBirthday, saplingActivation: network.constants.SAPLING_ACTIVATION_HEIGHT, network: network)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: walletBirthday, saplingActivation: network.constants.saplingActivationHeight, network: network)
var info = LightdInfo()
info.blockHeight = UInt64(expectedLatestHeight)
info.branch = "d34db33f"
info.chainName = "main"
info.buildUser = "test user"
info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
service.mockLightDInfo = info
let mockRust = MockRustBackend.self

View File

@ -40,8 +40,8 @@ class BlockDownloaderTests: XCTestCase {
let expect = XCTestExpectation(description: self.description)
expect.expectedFulfillmentCount = 3
let lowerRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT
let upperRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT + 99
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange))
downloader.downloadBlockRange(range) { (error) in
@ -66,8 +66,8 @@ class BlockDownloaderTests: XCTestCase {
func testSmallDownload() {
let lowerRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT
let upperRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT + 99
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange))
var latest: BlockHeight = 0
@ -94,12 +94,12 @@ class BlockDownloaderTests: XCTestCase {
}
func testFailure() {
let awfulDownloader = CompactBlockDownloader(service: AwfulLightWalletService(latestBlockHeight: self.network.constants.SAPLING_ACTIVATION_HEIGHT + 1000, service: darksideWalletService), storage: ZcashConsoleFakeStorage())
let awfulDownloader = CompactBlockDownloader(service: AwfulLightWalletService(latestBlockHeight: self.network.constants.saplingActivationHeight + 1000, service: darksideWalletService), storage: ZcashConsoleFakeStorage())
let expect = XCTestExpectation(description: self.description)
expect.expectedFulfillmentCount = 1
let lowerRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT
let upperRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT + 99
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange))

View File

@ -55,7 +55,7 @@ class BlockScanOperationTests: XCTestCase {
let latestScannedBlockExpect = XCTestExpectation(description: self.description + "latestScannedHeight")
let service = LightWalletGRPCService(endpoint: LightWalletEndpoint(address: "lightwalletd.testnet.electriccoin.co", port: 9067))
let blockCount = 100
let range = network.constants.SAPLING_ACTIVATION_HEIGHT ... network.constants.SAPLING_ACTIVATION_HEIGHT + blockCount
let range = network.constants.saplingActivationHeight ... network.constants.saplingActivationHeight + blockCount
let downloadOperation = CompactBlockDownloadOperation(downloader: CompactBlockDownloader.sqlDownloader(service: service, at: cacheDbURL)!, range: range)
let scanOperation = CompactBlockScanningOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL, networkType: network.networkType)

View File

@ -10,7 +10,7 @@ import XCTest
@testable import ZcashLightClientKit
class CompactBlockProcessorTests: XCTestCase {
let processorConfig = CompactBlockProcessor.Configuration.standard(for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.SAPLING_ACTIVATION_HEIGHT)
let processorConfig = CompactBlockProcessor.Configuration.standard(for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight)
var processor: CompactBlockProcessor!
var downloadStartedExpect: XCTestExpectation!
var updatedNotificationExpectation: XCTestExpectation!
@ -19,7 +19,7 @@ class CompactBlockProcessorTests: XCTestCase {
var startedValidatingNotificationExpectation: XCTestExpectation!
var idleNotificationExpectation: XCTestExpectation!
let network = ZcashNetworkBuilder.network(for: .testnet)
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.SAPLING_ACTIVATION_HEIGHT + 2000
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
@ -35,7 +35,7 @@ class CompactBlockProcessorTests: XCTestCase {
info.chainName = "test"
info.consensusBranchID = branchID.toString()
info.estimatedHeight = UInt64(mockLatestHeight)
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
})
let storage = CompactBlockStorage.init(connectionProvider: SimpleConnectionProvider(path: processorConfig.cacheDb.absoluteString))
@ -123,15 +123,15 @@ class CompactBlockProcessorTests: XCTestCase {
// test first range
var latestDownloadedHeight = processorConfig.walletBirthday // this can be either this or Wallet Birthday.
var latestBlockchainHeight = BlockHeight(network.constants.SAPLING_ACTIVATION_HEIGHT + 1000)
var latestBlockchainHeight = BlockHeight(network.constants.saplingActivationHeight + 1000)
var expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight, upper:latestBlockchainHeight))
XCTAssertEqual(expectedBatchRange, CompactBlockProcessor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight, walletBirthday: processorConfig.walletBirthday))
// Test mid-range
latestDownloadedHeight = BlockHeight(network.constants.SAPLING_ACTIVATION_HEIGHT + ZcashSDK.DEFAULT_BATCH_SIZE)
latestBlockchainHeight = BlockHeight(network.constants.SAPLING_ACTIVATION_HEIGHT + 1000)
latestDownloadedHeight = BlockHeight(network.constants.saplingActivationHeight + ZcashSDK.DefaultBatchSize)
latestBlockchainHeight = BlockHeight(network.constants.saplingActivationHeight + 1000)
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))
@ -139,8 +139,8 @@ class CompactBlockProcessorTests: XCTestCase {
// Test last batch range
latestDownloadedHeight = BlockHeight(network.constants.SAPLING_ACTIVATION_HEIGHT + 950)
latestBlockchainHeight = BlockHeight(network.constants.SAPLING_ACTIVATION_HEIGHT + 1000)
latestDownloadedHeight = BlockHeight(network.constants.saplingActivationHeight + 950)
latestBlockchainHeight = BlockHeight(network.constants.saplingActivationHeight + 1000)
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))

View File

@ -11,7 +11,7 @@ import XCTest
@testable import ZcashLightClientKit
class CompactBlockReorgTests: XCTestCase {
let processorConfig = CompactBlockProcessor.Configuration.standard(for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.SAPLING_ACTIVATION_HEIGHT)
let processorConfig = CompactBlockProcessor.Configuration.standard(for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight)
var processor: CompactBlockProcessor!
var downloadStartedExpect: XCTestExpectation!
var updatedNotificationExpectation: XCTestExpectation!
@ -21,7 +21,7 @@ class CompactBlockReorgTests: XCTestCase {
var idleNotificationExpectation: XCTestExpectation!
var reorgNotificationExpectation: XCTestExpectation!
let network = ZcashNetworkBuilder.network(for: .testnet)
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.SAPLING_ACTIVATION_HEIGHT + 2000
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
@ -38,7 +38,7 @@ class CompactBlockReorgTests: XCTestCase {
info.chainName = "test"
info.consensusBranchID = branchID.toString()
info.estimatedHeight = UInt64(mockLatestHeight)
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
})
try ZcashRustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: .testnet)
@ -49,7 +49,7 @@ class CompactBlockReorgTests: XCTestCase {
let mockBackend = MockRustBackend.self
mockBackend.mockValidateCombinedChainFailAfterAttempts = 3
mockBackend.mockValidateCombinedChainKeepFailing = false
mockBackend.mockValidateCombinedChainFailureHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT + 320
mockBackend.mockValidateCombinedChainFailureHeight = self.network.constants.saplingActivationHeight + 320
processor = CompactBlockProcessor(service: service,
storage: storage,
@ -86,8 +86,8 @@ class CompactBlockReorgTests: XCTestCase {
XCTAssertNotNil(notification.userInfo)
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
XCTAssertTrue( reorg == 0 || reorg > self.network.constants.SAPLING_ACTIVATION_HEIGHT)
XCTAssertTrue( rewind == 0 || rewind > self.network.constants.SAPLING_ACTIVATION_HEIGHT)
XCTAssertTrue( reorg == 0 || reorg > self.network.constants.saplingActivationHeight)
XCTAssertTrue( rewind == 0 || rewind > self.network.constants.saplingActivationHeight)
XCTAssertTrue( rewind <= reorg )
reorgNotificationExpectation.fulfill()
} else {

View File

@ -20,7 +20,7 @@ class CompactBlockStorageTests: XCTestCase {
func testStoreThousandBlocks() {
let initialHeight = try! compactBlockDao.latestHeight()
let startHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT
let startHeight = self.network.constants.saplingActivationHeight
let blockCount = Int(1_000)
let finalHeight = startHeight + blockCount
@ -63,7 +63,7 @@ class CompactBlockStorageTests: XCTestCase {
func testRewindTo() {
let startHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT
let startHeight = self.network.constants.saplingActivationHeight
let blockCount = Int(1_000)
let finalHeight = startHeight + blockCount

View File

@ -25,7 +25,7 @@ class DownloadOperationTests: XCTestCase {
let storage = try! TestDbBuilder.inMemoryCompactBlockStorage()
let downloader = CompactBlockDownloader(service: service, storage: storage)
let blockCount = 100
let activationHeight = network.constants.SAPLING_ACTIVATION_HEIGHT
let activationHeight = network.constants.saplingActivationHeight
let range = activationHeight ... activationHeight + blockCount
let downloadOperation = CompactBlockDownloadOperation(downloader: downloader, range: range)

View File

@ -40,8 +40,8 @@ class LightWalletServiceTests: XCTestCase {
func testHundredBlocks() {
let expect = XCTestExpectation(description: self.description)
let count = 99
let lowerRange: BlockHeight = network.constants.SAPLING_ACTIVATION_HEIGHT
let upperRange: BlockHeight = network.constants.SAPLING_ACTIVATION_HEIGHT + count
let lowerRange: BlockHeight = network.constants.saplingActivationHeight
let upperRange: BlockHeight = network.constants.saplingActivationHeight + count
let blockRange = lowerRange ... upperRange
service.blockRange(blockRange) { (result) in
@ -61,8 +61,8 @@ class LightWalletServiceTests: XCTestCase {
}
func testSyncBlockRange() {
let lowerRange: BlockHeight = network.constants.SAPLING_ACTIVATION_HEIGHT
let upperRange: BlockHeight = network.constants.SAPLING_ACTIVATION_HEIGHT + 99
let lowerRange: BlockHeight = network.constants.saplingActivationHeight
let upperRange: BlockHeight = network.constants.saplingActivationHeight + 99
let blockRange = lowerRange ... upperRange
do {
@ -81,7 +81,7 @@ class LightWalletServiceTests: XCTestCase {
case .failure(let e):
XCTFail("error: \(e)")
case .success(let height):
XCTAssertTrue(height > self.network.constants.SAPLING_ACTIVATION_HEIGHT)
XCTAssertTrue(height > self.network.constants.saplingActivationHeight)
}
}

View File

@ -49,7 +49,7 @@ class NetworkUpgradeTests: XCTestCase {
let firstSyncExpectation = XCTestExpectation(description: "first sync")
try coordinator.applyStaged(blockheight: activationHeight - ZcashSDK.DEFAULT_STALE_TOLERANCE)
try coordinator.applyStaged(blockheight: activationHeight - ZcashSDK.defaultStaleTolerance)
sleep(5)
try coordinator.sync(completion: { (synchronizer) in

View File

@ -286,8 +286,8 @@ class TestSynchronizerBuilder {
dataDb: initializer.dataDbURL,
downloadBatchSize: 100,
retries: 5,
maxBackoffInterval: ZcashSDK.DEFAULT_MAX_BACKOFF_INTERVAL,
rewindDistance: ZcashSDK.DEFAULT_REWIND_DISTANCE,
maxBackoffInterval: ZcashSDK.defaultMaxBackOffInterval,
rewindDistance: ZcashSDK.defaultRewindDistance,
walletBirthday: walletBirthday.height,
saplingActivation: lowerBoundHeight,
network: network)

View File

@ -202,31 +202,30 @@ class DarksideWalletService: LightWalletService {
class DarksideWalletDConstants: NetworkConstants {
static var SAPLING_ACTIVATION_HEIGHT: BlockHeight {
static var saplingActivationHeight: BlockHeight {
663150
}
static var DEFAULT_DATA_DB_NAME: String {
ZcashSDKMainnetConstants.DEFAULT_DATA_DB_NAME
static var defaultDataDbName: String {
ZcashSDKMainnetConstants.defaultDataDbName
}
static var DEFAULT_CACHES_DB_NAME: String {
ZcashSDKMainnetConstants.DEFAULT_CACHES_DB_NAME
static var defaultCacheDbName: String {
ZcashSDKMainnetConstants.defaultCacheDbName
}
static var DEFAULT_PENDING_DB_NAME: String {
ZcashSDKMainnetConstants.DEFAULT_PENDING_DB_NAME
static var defaultPendingDbName: String {
ZcashSDKMainnetConstants.defaultPendingDbName
}
static var DEFAULT_DB_NAME_PREFIX: String {
ZcashSDKMainnetConstants.DEFAULT_DB_NAME_PREFIX
static var defaultDbNamePrefix: String {
ZcashSDKMainnetConstants.defaultDbNamePrefix
}
static var FEE_CHANGE_HEIGHT: BlockHeight {
ZcashSDKMainnetConstants.FEE_CHANGE_HEIGHT
static var feeChangeHeight: BlockHeight {
ZcashSDKMainnetConstants.feeChangeHeight
}
}
class DarksideWalletDNetwork: ZcashNetwork {
var constants: NetworkConstants.Type = DarksideWalletDConstants.self

View File

@ -79,7 +79,7 @@ class FakeChainBuilder {
try darksideWallet.useDataset(testnetCanopyStartBlock)
try darksideWallet.stageBlocksCreate(from: birthday + 1, count: length)
try darksideWallet.stageTransaction(from: testnetPreCanopyTx, at: networkActivationHeight - ZcashSDK.EXPIRY_OFFSET)
try darksideWallet.stageTransaction(from: testnetPreCanopyTx, at: networkActivationHeight - ZcashSDK.expiryOffset)
}
@ -96,7 +96,7 @@ class FakeChainBuilder {
static func buildChainMixedFunds(darksideWallet: DarksideWalletService, birthday: BlockHeight, networkActivationHeight: BlockHeight, branchID: String, chainName: String, length: Int) throws {
try buildChain(darksideWallet: darksideWallet, birthday: birthday, networkActivationHeight: networkActivationHeight, branchID: branchID, chainName: chainName, length: length)
try darksideWallet.stageTransaction(from: testnetPostCanopyTx, at: networkActivationHeight + ZcashSDK.EXPIRY_OFFSET)
try darksideWallet.stageTransaction(from: testnetPostCanopyTx, at: networkActivationHeight + ZcashSDK.expiryOffset)
}

View File

@ -144,16 +144,16 @@ class MockTransactionRepository: TransactionRepository {
}
func mockSent(_ index: Int) -> ConfirmedTransactionEntity {
ConfirmedTransaction(toAddress: "some_address", expiryHeight: BlockHeight.max, minedHeight: randomBlockHeight(), noteId: index, blockTimeInSeconds: randomTimeInterval(), transactionIndex: index, raw: Data(), id: index, value: Int.random(in: 1 ... ZcashSDK.ZATOSHI_PER_ZEC), memo: nil, rawTransactionId: Data())
ConfirmedTransaction(toAddress: "some_address", expiryHeight: BlockHeight.max, minedHeight: randomBlockHeight(), noteId: index, blockTimeInSeconds: randomTimeInterval(), transactionIndex: index, raw: Data(), id: index, value: Int.random(in: 1 ... ZcashSDK.zatoshiPerZEC), memo: nil, rawTransactionId: Data())
}
func mockReceived(_ index: Int) -> ConfirmedTransactionEntity {
ConfirmedTransaction(toAddress: nil, expiryHeight: BlockHeight.max, minedHeight: randomBlockHeight(), noteId: index, blockTimeInSeconds: randomTimeInterval(), transactionIndex: index, raw: Data(), id: index, value: Int.random(in: 1 ... ZcashSDK.ZATOSHI_PER_ZEC), memo: nil, rawTransactionId: Data())
ConfirmedTransaction(toAddress: nil, expiryHeight: BlockHeight.max, minedHeight: randomBlockHeight(), noteId: index, blockTimeInSeconds: randomTimeInterval(), transactionIndex: index, raw: Data(), id: index, value: Int.random(in: 1 ... ZcashSDK.zatoshiPerZEC), memo: nil, rawTransactionId: Data())
}
func randomBlockHeight() -> BlockHeight {
BlockHeight.random(in: network.constants.SAPLING_ACTIVATION_HEIGHT ... 1_000_000)
BlockHeight.random(in: network.constants.saplingActivationHeight ... 1_000_000)
}
func randomTimeInterval() -> TimeInterval {
Double.random(in: Date().timeIntervalSince1970 - 1000000.0 ... Date().timeIntervalSince1970)

View File

@ -322,7 +322,7 @@ class MockRustBackend: ZcashRustBackendWelding {
nil
}
static func decryptAndStoreTransaction(dbData: URL, tx: [UInt8], minedHeight: Int32, networkType: NetworkType) -> Bool {
static func decryptAndStoreTransaction(dbData: URL, txBytes: [UInt8], minedHeight: Int32, networkType: NetworkType) -> Bool {
false
}