Clear SwiftLint on ZcashLightClientKit
This commit is contained in:
parent
185cbb4b91
commit
b1a0b01673
|
@ -5,6 +5,7 @@
|
||||||
// Created by Francisco Gindre on 06/09/2019.
|
// Created by Francisco Gindre on 06/09/2019.
|
||||||
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
||||||
//
|
//
|
||||||
|
// swiftlint:disable all
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import ZcashLightClientKit
|
import ZcashLightClientKit
|
||||||
|
@ -33,14 +34,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
if let wallet = wallet {
|
if let wallet = wallet {
|
||||||
return wallet
|
return wallet
|
||||||
} else {
|
} else {
|
||||||
let unifiedViewingKeys = try! DerivationTool(networkType: ZCASH_NETWORK.networkType).deriveUnifiedViewingKeysFromSeed(DemoAppConfig.seed, numberOfAccounts: 1)
|
let unifiedViewingKeys = try! DerivationTool(networkType: kZcashNetwork.networkType).deriveUnifiedViewingKeysFromSeed(DemoAppConfig.seed, numberOfAccounts: 1)
|
||||||
let wallet = Initializer(cacheDbURL:try! __cacheDbURL(),
|
let wallet = Initializer(cacheDbURL:try! cacheDbURLHelper(),
|
||||||
dataDbURL: try! __dataDbURL(),
|
dataDbURL: try! dataDbURLHelper(),
|
||||||
pendingDbURL: try! __pendingDbURL(),
|
pendingDbURL: try! pendingDbURLHelper(),
|
||||||
endpoint: DemoAppConfig.endpoint,
|
endpoint: DemoAppConfig.endpoint,
|
||||||
network: ZCASH_NETWORK,
|
network: kZcashNetwork,
|
||||||
spendParamsURL: try! __spendParamsURL(),
|
spendParamsURL: try! spendParamsURLHelper(),
|
||||||
outputParamsURL: try! __outputParamsURL(),
|
outputParamsURL: try! outputParamsURLHelper(),
|
||||||
viewingKeys: unifiedViewingKeys,
|
viewingKeys: unifiedViewingKeys,
|
||||||
walletBirthday: DemoAppConfig.birthdayHeight,
|
walletBirthday: DemoAppConfig.birthdayHeight,
|
||||||
loggerProxy: loggerProxy)
|
loggerProxy: loggerProxy)
|
||||||
|
@ -49,7 +50,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
try! wallet.initialize()
|
try! wallet.initialize()
|
||||||
var storage = SampleStorage.shared
|
var storage = SampleStorage.shared
|
||||||
storage!.seed = Data(DemoAppConfig.seed)
|
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
|
self.wallet = wallet
|
||||||
return wallet
|
return wallet
|
||||||
}
|
}
|
||||||
|
@ -65,7 +66,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
return
|
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!")) {}
|
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 {
|
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||||
|
@ -112,19 +112,19 @@ extension AppDelegate {
|
||||||
|
|
||||||
func clearDatabases() {
|
func clearDatabases() {
|
||||||
do {
|
do {
|
||||||
try FileManager.default.removeItem(at: try __cacheDbURL())
|
try FileManager.default.removeItem(at: try cacheDbURLHelper())
|
||||||
} catch {
|
} catch {
|
||||||
loggerProxy.error("error clearing cache DB: \(error)")
|
loggerProxy.error("error clearing cache DB: \(error)")
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try FileManager.default.removeItem(at: try __dataDbURL())
|
try FileManager.default.removeItem(at: try dataDbURLHelper())
|
||||||
} catch {
|
} catch {
|
||||||
loggerProxy.error("error clearing data db: \(error)")
|
loggerProxy.error("error clearing data db: \(error)")
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try FileManager.default.removeItem(at: try __pendingDbURL())
|
try FileManager.default.removeItem(at: try pendingDbURLHelper())
|
||||||
} catch {
|
} catch {
|
||||||
loggerProxy.error("error clearing data db: \(error)")
|
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)
|
try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func __cacheDbURL() throws -> URL {
|
func cacheDbURLHelper() throws -> URL {
|
||||||
try __documentsDirectory().appendingPathComponent(ZCASH_NETWORK.constants.DEFAULT_DB_NAME_PREFIX+ZcashSDK.DEFAULT_CACHES_DB_NAME, isDirectory: false)
|
try documentsDirectoryHelper().appendingPathComponent(kZcashNetwork.constants.defaultDbNamePrefix+ZcashSDK.defaultCacheDbName, isDirectory: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func __dataDbURL() throws -> URL {
|
func dataDbURLHelper() throws -> URL {
|
||||||
try __documentsDirectory().appendingPathComponent(ZCASH_NETWORK.constants.DEFAULT_DB_NAME_PREFIX+ZcashSDK.DEFAULT_DATA_DB_NAME, isDirectory: false)
|
try documentsDirectoryHelper().appendingPathComponent(kZcashNetwork.constants.defaultDbNamePrefix+ZcashSDK.defaultDataDbName, isDirectory: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func __pendingDbURL() throws -> URL {
|
func pendingDbURLHelper() throws -> URL {
|
||||||
try __documentsDirectory().appendingPathComponent(ZCASH_NETWORK.constants.DEFAULT_DB_NAME_PREFIX+ZcashSDK.DEFAULT_PENDING_DB_NAME)
|
try documentsDirectoryHelper().appendingPathComponent(kZcashNetwork.constants.defaultDbNamePrefix+ZcashSDK.defaultPendingDbName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func __spendParamsURL() throws -> URL {
|
func spendParamsURLHelper() throws -> URL {
|
||||||
try __documentsDirectory().appendingPathComponent("sapling-spend.params")
|
try documentsDirectoryHelper().appendingPathComponent("sapling-spend.params")
|
||||||
}
|
}
|
||||||
|
|
||||||
func __outputParamsURL() throws -> URL {
|
func outputParamsURLHelper() throws -> URL {
|
||||||
try __documentsDirectory().appendingPathComponent("sapling-output.params")
|
try documentsDirectoryHelper().appendingPathComponent("sapling-output.params")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public extension NotificationBubble {
|
public extension NotificationBubble {
|
||||||
static func sucessOptions(animation: NotificationBubble.Animation) -> [NotificationBubble.Style] {
|
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.margins(UIEdgeInsets(top: 40, left: 0, bottom: 0, right: 0)),
|
||||||
NotificationBubble.Style.cornerRadius(8),
|
NotificationBubble.Style.cornerRadius(8),
|
||||||
NotificationBubble.Style.duration(timeInterval: 10),
|
NotificationBubble.Style.duration(timeInterval: 10),
|
||||||
NotificationBubble.Style.backgroundColor(UIColor.green)]
|
NotificationBubble.Style.backgroundColor(UIColor.green)
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,4 +9,4 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import ZcashLightClientKit
|
import ZcashLightClientKit
|
||||||
|
|
||||||
let ZCASH_NETWORK = ZcashNetworkBuilder.network(for: .mainnet)
|
let kZcashNetwork = ZcashNetworkBuilder.network(for: .mainnet)
|
||||||
|
|
|
@ -9,4 +9,4 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import ZcashLightClientKit
|
import ZcashLightClientKit
|
||||||
|
|
||||||
let ZCASH_NETWORK = ZcashNetworkBuilder.network(for: .testnet)
|
let kZcashNetwork = ZcashNetworkBuilder.network(for: .testnet)
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import ZcashLightClientKit
|
import ZcashLightClientKit
|
||||||
import MnemonicSwift
|
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 host = ZcashSDK.isMainnet ? "lightwalletd.electriccoin.co" : "lightwalletd.testnet.electriccoin.co"
|
||||||
static var port: Int = 9067
|
static var port: Int = 9067
|
||||||
static var birthdayHeight: BlockHeight = ZcashSDK.isMainnet ? 935000 : 1386000
|
static var birthdayHeight: BlockHeight = ZcashSDK.isMainnet ? 935000 : 1386000
|
||||||
|
@ -20,7 +21,7 @@ struct DemoAppConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
static var processorConfig: CompactBlockProcessor.Configuration = {
|
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 {
|
static var endpoint: LightWalletEndpoint {
|
||||||
|
@ -31,7 +32,7 @@ struct DemoAppConfig {
|
||||||
|
|
||||||
extension ZcashSDK {
|
extension ZcashSDK {
|
||||||
static var isMainnet: Bool {
|
static var isMainnet: Bool {
|
||||||
switch ZCASH_NETWORK.networkType {
|
switch kZcashNetwork.networkType {
|
||||||
case .mainnet:
|
case .mainnet:
|
||||||
return true
|
return true
|
||||||
case .testnet:
|
case .testnet:
|
||||||
|
|
|
@ -83,7 +83,7 @@ class DerivationToolViewController: UIViewController {
|
||||||
func deriveFrom(seedPhrase: String) throws {
|
func deriveFrom(seedPhrase: String) throws {
|
||||||
|
|
||||||
let seedBytes = try Mnemonic.deterministicSeedBytes(from: seedPhrase)
|
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 {
|
guard let spendingKey = try derivationTool.deriveSpendingKeys(seed: seedBytes, numberOfAccounts: 1).first else {
|
||||||
throw DerivationErrors.couldNotDeriveSpendingKeys(underlyingError: DerivationErrors.unknown)
|
throw DerivationErrors.couldNotDeriveSpendingKeys(underlyingError: DerivationErrors.unknown)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ class GetAddressViewController: UIViewController {
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
let derivationTool = DerivationTool(networkType: ZCASH_NETWORK.networkType)
|
let derivationTool = DerivationTool(networkType: kZcashNetwork.networkType)
|
||||||
// Do any additional setup after loading the view.
|
// Do any additional setup after loading the view.
|
||||||
|
|
||||||
zAddressLabel.text = (try? derivationTool.deriveShieldedAddress(seed: DemoAppConfig.seed, accountIndex: 0)) ?? "No Addresses found"
|
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) {
|
@IBAction func addressTapped(_ gesture: UIGestureRecognizer) {
|
||||||
loggerProxy.event("copied to clipboard")
|
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)
|
let alert = UIAlertController(title: "", message: "Address Copied to clipboard", preferredStyle: UIAlertController.Style.alert)
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
|
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
|
||||||
self.present(alert, animated: true, completion: nil)
|
self.present(alert, animated: true, completion: nil)
|
||||||
|
@ -68,7 +68,7 @@ class GetAddressViewController: UIViewController {
|
||||||
|
|
||||||
@IBAction func tAddressTapped(_ gesture: UIGestureRecognizer) {
|
@IBAction func tAddressTapped(_ gesture: UIGestureRecognizer) {
|
||||||
loggerProxy.event("copied to clipboard")
|
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)
|
let alert = UIAlertController(title: "", message: "Address Copied to clipboard", preferredStyle: UIAlertController.Style.alert)
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
|
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
|
||||||
self.present(alert, animated: true, completion: nil)
|
self.present(alert, animated: true, completion: nil)
|
||||||
|
|
|
@ -35,12 +35,12 @@ class GetBalanceViewController: UIViewController {
|
||||||
|
|
||||||
extension Int64 {
|
extension Int64 {
|
||||||
func asHumanReadableZecBalance() -> Double {
|
func asHumanReadableZecBalance() -> Double {
|
||||||
Double(self) / Double(ZcashSDK.ZATOSHI_PER_ZEC)
|
Double(self) / Double(ZcashSDK.zatoshiPerZEC)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Double {
|
extension Double {
|
||||||
func toZatoshi() -> Int64 {
|
func toZatoshi() -> Int64 {
|
||||||
Int64(self * Double(ZcashSDK.ZATOSHI_PER_ZEC))
|
Int64(self * Double(ZcashSDK.zatoshiPerZEC))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ class GetUTXOsViewController: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUI() {
|
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
|
self.transparentAddressLabel.text = tAddress
|
||||||
|
|
||||||
let balance = try! AppDelegate.shared.sharedSynchronizer.getTransparentBalance(accountIndex: 0)
|
let balance = try! AppDelegate.shared.sharedSynchronizer.getTransparentBalance(accountIndex: 0)
|
||||||
|
@ -38,7 +38,7 @@ class GetUTXOsViewController: UIViewController {
|
||||||
@IBAction func shieldFunds(_ sender: Any) {
|
@IBAction func shieldFunds(_ sender: Any) {
|
||||||
do {
|
do {
|
||||||
let seed = DemoAppConfig.seed
|
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 sk = try derivationTool.deriveSpendingKeys(seed: seed, numberOfAccounts: 1).first!
|
||||||
|
|
||||||
let tsk = try derivationTool.deriveTransparentPrivateKey(seed: seed)
|
let tsk = try derivationTool.deriveTransparentPrivateKey(seed: seed)
|
||||||
|
|
|
@ -5,12 +5,11 @@
|
||||||
// Created by Francisco Gindre on 12/20/19.
|
// Created by Francisco Gindre on 12/20/19.
|
||||||
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
||||||
//
|
//
|
||||||
|
// swiftlint:disable line_length force_try
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
protocol WalletStorage {
|
protocol WalletStorage {
|
||||||
var seed: Data? {get set}
|
var seed: Data? { get set }
|
||||||
var privateKey: String? { get set }
|
var privateKey: String? { get set }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,24 +24,23 @@ class SampleStorage: WalletStorage {
|
||||||
static var shared: WalletStorage! {
|
static var shared: WalletStorage! {
|
||||||
_shared
|
_shared
|
||||||
}
|
}
|
||||||
private let KEY_SEED = "cash.z.wallet.sdk.demoapp.SEED"
|
private let keySeed = "cash.z.wallet.sdk.demoapp.SEED"
|
||||||
private let KEY_PK = "cash.z.wallet.sdk.demoapp.PK"
|
private let keyPK = "cash.z.wallet.sdk.demoapp.PK"
|
||||||
var seed: Data? {
|
var seed: Data? {
|
||||||
set {
|
set {
|
||||||
UserDefaults.standard.set(newValue, forKey: KEY_SEED)
|
UserDefaults.standard.set(newValue, forKey: keySeed)
|
||||||
}
|
}
|
||||||
get {
|
get {
|
||||||
UserDefaults.standard.value(forKey: KEY_SEED) as! Data?
|
UserDefaults.standard.value(forKey: keySeed) as! Data?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var privateKey: String? {
|
var privateKey: String? {
|
||||||
set {
|
set {
|
||||||
UserDefaults.standard.set(newValue, forKey: KEY_PK)
|
UserDefaults.standard.set(newValue, forKey: keyPK)
|
||||||
}
|
}
|
||||||
get {
|
get {
|
||||||
UserDefaults.standard.value(forKey: KEY_PK) as! String?
|
UserDefaults.standard.value(forKey: keyPK) as! String?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,8 @@ class SaplingParametersViewController: UIViewController {
|
||||||
@IBOutlet weak var deleteButton: UIButton!
|
@IBOutlet weak var deleteButton: UIButton!
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
let spendParamPath = try! __spendParamsURL().path
|
let spendParamPath = try! spendParamsURLHelper().path
|
||||||
let outputParamPath = try! __outputParamsURL().path
|
let outputParamPath = try! outputParamsURLHelper().path
|
||||||
// Do any additional setup after loading the view.
|
// Do any additional setup after loading the view.
|
||||||
self.spendPath.text = spendParamPath
|
self.spendPath.text = spendParamPath
|
||||||
self.outputPath.text = outputParamPath
|
self.outputPath.text = outputParamPath
|
||||||
|
@ -29,14 +29,14 @@ class SaplingParametersViewController: UIViewController {
|
||||||
self.updateButtons()
|
self.updateButtons()
|
||||||
}
|
}
|
||||||
func updateButtons() {
|
func updateButtons() {
|
||||||
let spendParamPath = try! __spendParamsURL().path
|
let spendParamPath = try! spendParamsURLHelper().path
|
||||||
let outputParamPath = try! __outputParamsURL().path
|
let outputParamPath = try! outputParamsURLHelper().path
|
||||||
self.downloadButton.isHidden = fileExists(outputParamPath) && fileExists(spendParamPath)
|
self.downloadButton.isHidden = fileExists(outputParamPath) && fileExists(spendParamPath)
|
||||||
self.deleteButton.isHidden = !(fileExists(outputParamPath) || fileExists(spendParamPath))
|
self.deleteButton.isHidden = !(fileExists(outputParamPath) || fileExists(spendParamPath))
|
||||||
}
|
}
|
||||||
func updateColor() {
|
func updateColor() {
|
||||||
let spendParamPath = try! __spendParamsURL().path
|
let spendParamPath = try! spendParamsURLHelper().path
|
||||||
let outputParamPath = try! __outputParamsURL().path
|
let outputParamPath = try! outputParamsURLHelper().path
|
||||||
self.spendPath.textColor = fileExists(spendParamPath) ? UIColor.green : UIColor.red
|
self.spendPath.textColor = fileExists(spendParamPath) ? UIColor.green : UIColor.red
|
||||||
self.outputPath.textColor = fileExists(outputParamPath) ? 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) {
|
@IBAction func download(_ sender: Any) {
|
||||||
let outputParameter = try! __outputParamsURL()
|
let outputParameter = try! outputParamsURLHelper()
|
||||||
let spendParameter = try! __spendParamsURL()
|
let spendParameter = try! spendParamsURLHelper()
|
||||||
SaplingParameterDownloader.downloadParamsIfnotPresent(spendURL: spendParameter, outputURL: outputParameter) { (result) in
|
SaplingParameterDownloader.downloadParamsIfnotPresent(spendURL: spendParameter, outputURL: outputParameter) { (result) in
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
@ -87,8 +87,8 @@ class SaplingParametersViewController: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func deleteFiles(_ sender: Any) {
|
@IBAction func deleteFiles(_ sender: Any) {
|
||||||
let spendParamURL = try! __spendParamsURL()
|
let spendParamURL = try! spendParamsURLHelper()
|
||||||
let outputParamURL = try! __outputParamsURL()
|
let outputParamURL = try! outputParamsURLHelper()
|
||||||
|
|
||||||
try? FileManager.default.removeItem(at: spendParamURL)
|
try? FileManager.default.removeItem(at: spendParamURL)
|
||||||
try? FileManager.default.removeItem(at: outputParamURL)
|
try? FileManager.default.removeItem(at: outputParamURL)
|
||||||
|
|
|
@ -173,8 +173,13 @@ class SendViewController: UIViewController {
|
||||||
|
|
||||||
KRProgressHUD.show()
|
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 {
|
DispatchQueue.main.async {
|
||||||
KRProgressHUD.dismiss()
|
KRProgressHUD.dismiss()
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,13 +37,13 @@ class CompactBlockStorage: CompactBlockDAO {
|
||||||
|
|
||||||
let db = try dbProvider.connection()
|
let db = try dbProvider.connection()
|
||||||
|
|
||||||
try db.run(compactBlocks.create(ifNotExists: true) { t in
|
try db.run(compactBlocks.create(ifNotExists: true) { table in
|
||||||
t.column(height, primaryKey: true)
|
table.column(height, primaryKey: true)
|
||||||
t.column(data)
|
table.column(data)
|
||||||
} )
|
}
|
||||||
|
)
|
||||||
|
|
||||||
try db.run(compactBlocks.createIndex(height, ifNotExists: true))
|
try db.run(compactBlocks.createIndex(height, ifNotExists: true))
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
throw StorageError.couldNotCreate
|
throw StorageError.couldNotCreate
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,6 @@ class CompactBlockStorage: CompactBlockDAO {
|
||||||
}
|
}
|
||||||
|
|
||||||
func latestBlockHeight() throws -> BlockHeight {
|
func latestBlockHeight() throws -> BlockHeight {
|
||||||
|
|
||||||
guard let maxHeight = try dbProvider.connection().scalar(compactBlocksTable().select(heightColumn().max)) else {
|
guard let maxHeight = try dbProvider.connection().scalar(compactBlocksTable().select(heightColumn().max)) else {
|
||||||
return BlockHeight.empty()
|
return BlockHeight.empty()
|
||||||
}
|
}
|
||||||
|
@ -82,7 +81,6 @@ class CompactBlockStorage: CompactBlockDAO {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension CompactBlockStorage: CompactBlockRepository {
|
extension CompactBlockStorage: CompactBlockRepository {
|
||||||
|
|
||||||
func latestHeight() throws -> BlockHeight {
|
func latestHeight() throws -> BlockHeight {
|
||||||
try latestBlockHeight()
|
try latestBlockHeight()
|
||||||
}
|
}
|
||||||
|
@ -117,11 +115,9 @@ extension CompactBlockStorage: CompactBlockRepository {
|
||||||
do {
|
do {
|
||||||
try self.rewind(to: height)
|
try self.rewind(to: height)
|
||||||
completion?(nil)
|
completion?(nil)
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
completion?(error)
|
completion?(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ class MigrationManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func migrateCacheDb() throws {
|
private func migrateCacheDb() throws {
|
||||||
let currentCacheDbVersion = try cacheDb.connection().getUserVersion()
|
let currentCacheDbVersion = try cacheDb.connection().getUserVersion()
|
||||||
|
|
||||||
LoggerProxy.debug("Attempting to perform migration for cache Db - currentVersion: \(currentCacheDbVersion). Latest version is: \(Self.latestCacheDbMigrationVersion)")
|
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()
|
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 {
|
if currentDataDbVersion < Self.latestDataDbMigrationVersion {
|
||||||
for v in (currentDataDbVersion + 1) ... Self.latestDataDbMigrationVersion {
|
for version in (currentDataDbVersion + 1) ... Self.latestDataDbMigrationVersion {
|
||||||
guard let version = DataDbMigrations.init(rawValue: v) else {
|
guard let version = DataDbMigrations.init(rawValue: version) else {
|
||||||
LoggerProxy.error("failed to determine migration version")
|
LoggerProxy.error("failed to determine migration version")
|
||||||
throw StorageError.invalidMigrationVersion(version: v)
|
throw StorageError.invalidMigrationVersion(version: version)
|
||||||
}
|
}
|
||||||
switch version {
|
switch version {
|
||||||
case .version1:
|
case .version1:
|
||||||
|
@ -95,7 +97,9 @@ class MigrationManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
func performVersion1Migration(viewingKeys: [UnifiedViewingKey]) throws {
|
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 db = try self.dataDb.connection()
|
||||||
|
|
||||||
let placeholder = "deriveMe"
|
let placeholder = "deriveMe"
|
||||||
|
@ -147,7 +151,10 @@ class MigrationManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
guard accounts.count == viewingKeys.count else {
|
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)
|
LoggerProxy.debug(message)
|
||||||
throw StorageError.migrationFailedWithMessage(message: message)
|
throw StorageError.migrationFailedWithMessage(message: message)
|
||||||
}
|
}
|
||||||
|
@ -189,10 +196,10 @@ class MigrationManager {
|
||||||
|
|
||||||
extension Connection {
|
extension Connection {
|
||||||
func getUserVersion() throws -> Int32 {
|
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 0
|
||||||
}
|
}
|
||||||
return Int32(v)
|
return Int32(version)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setUserVersion(_ version: Int32) throws {
|
func setUserVersion(_ version: Int32) throws {
|
||||||
|
|
|
@ -55,7 +55,6 @@ private extension Connection {
|
||||||
}
|
}
|
||||||
|
|
||||||
class SimpleConnectionProvider: ConnectionProvider {
|
class SimpleConnectionProvider: ConnectionProvider {
|
||||||
|
|
||||||
var path: String
|
var path: String
|
||||||
var readonly: Bool
|
var readonly: Bool
|
||||||
var db: Connection?
|
var db: Connection?
|
||||||
|
@ -66,12 +65,11 @@ class SimpleConnectionProvider: ConnectionProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
func connection() throws -> Connection {
|
func connection() throws -> Connection {
|
||||||
guard let c = db else {
|
guard let conn = db else {
|
||||||
let c = try Connection(path, readonly: readonly)
|
let conn = try Connection(path, readonly: readonly)
|
||||||
self.db = c
|
self.db = conn
|
||||||
return c
|
return conn
|
||||||
}
|
}
|
||||||
return c
|
return conn
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,14 +196,12 @@ extension CompactBlockDownloader: CompactBlockDownloading {
|
||||||
}
|
}
|
||||||
|
|
||||||
func rewind(to height: BlockHeight, completion: @escaping (Error?) -> Void) {
|
func rewind(to height: BlockHeight, completion: @escaping (Error?) -> Void) {
|
||||||
|
|
||||||
storage.rewind(to: height) { (e) in
|
storage.rewind(to: height) { (e) in
|
||||||
completion(e)
|
completion(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func lastDownloadedBlockHeight(result: @escaping (Result<BlockHeight,Error>) -> Void) {
|
func lastDownloadedBlockHeight(result: @escaping (Result<BlockHeight,Error>) -> Void) {
|
||||||
|
|
||||||
storage.latestHeight { (r) in
|
storage.latestHeight { (r) in
|
||||||
switch r {
|
switch r {
|
||||||
case .failure(let e):
|
case .failure(let e):
|
||||||
|
@ -223,12 +221,12 @@ extension CompactBlockDownloader: CompactBlockDownloading {
|
||||||
try self.storage.latestHeight()
|
try self.storage.latestHeight()
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchTransaction(txId: Data) throws -> TransactionEntity{
|
func fetchTransaction(txId: Data) throws -> TransactionEntity {
|
||||||
try lightwalletService.fetchTransaction(txId: txId)
|
try lightwalletService.fetchTransaction(txId: txId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, Error>) -> Void) {
|
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, Error>) -> Void) {
|
||||||
lightwalletService.fetchTransaction(txId: txId) { (txResult) in
|
lightwalletService.fetchTransaction(txId: txId) { txResult in
|
||||||
switch txResult {
|
switch txResult {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
result(.failure(error))
|
result(.failure(error))
|
||||||
|
|
|
@ -81,7 +81,6 @@ class CompactBlockStreamDownloadOperation: ZcashOperation {
|
||||||
}
|
}
|
||||||
self.startedHandler?()
|
self.startedHandler?()
|
||||||
do {
|
do {
|
||||||
|
|
||||||
if self.targetHeight == nil {
|
if self.targetHeight == nil {
|
||||||
self.targetHeight = try service.latestBlockHeight()
|
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
|
self.cancelable = self.service.blockStream(startHeight: startHeight, endHeight: latestHeight) { [weak self] result in
|
||||||
switch result {
|
switch result {
|
||||||
|
|
||||||
case .success(let r):
|
case .success(let r):
|
||||||
switch r {
|
switch r {
|
||||||
case .ok:
|
case .ok:
|
||||||
|
@ -109,7 +107,6 @@ class CompactBlockStreamDownloadOperation: ZcashOperation {
|
||||||
self?.fail(error: e)
|
self?.fail(error: e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} handler: {[weak self] block in
|
} handler: {[weak self] block in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
do {
|
do {
|
||||||
|
@ -156,14 +153,15 @@ class CompactBlockBatchDownloadOperation: ZcashOperation {
|
||||||
private var startHeight: BlockHeight
|
private var startHeight: BlockHeight
|
||||||
private var targetHeight: BlockHeight
|
private var targetHeight: BlockHeight
|
||||||
private weak var progressDelegate: CompactBlockProgressDelegate?
|
private weak var progressDelegate: CompactBlockProgressDelegate?
|
||||||
required init(service: LightWalletService,
|
required init(
|
||||||
storage: CompactBlockStorage,
|
service: LightWalletService,
|
||||||
startHeight: BlockHeight,
|
storage: CompactBlockStorage,
|
||||||
targetHeight: BlockHeight,
|
startHeight: BlockHeight,
|
||||||
batchSize: Int = 100,
|
targetHeight: BlockHeight,
|
||||||
maxRetries: Int = 5,
|
batchSize: Int = 100,
|
||||||
progressDelegate: CompactBlockProgressDelegate? = nil) {
|
maxRetries: Int = 5,
|
||||||
|
progressDelegate: CompactBlockProgressDelegate? = nil
|
||||||
|
) {
|
||||||
self.storage = storage
|
self.storage = storage
|
||||||
self.service = service
|
self.service = service
|
||||||
self.startHeight = startHeight
|
self.startHeight = startHeight
|
||||||
|
@ -182,7 +180,6 @@ class CompactBlockBatchDownloadOperation: ZcashOperation {
|
||||||
}
|
}
|
||||||
self.startedHandler?()
|
self.startedHandler?()
|
||||||
do {
|
do {
|
||||||
|
|
||||||
let localDownloadedHeight = try self.storage.latestHeight()
|
let localDownloadedHeight = try self.storage.latestHeight()
|
||||||
|
|
||||||
if localDownloadedHeight != BlockHeight.empty() && localDownloadedHeight > startHeight {
|
if localDownloadedHeight != BlockHeight.empty() && localDownloadedHeight > startHeight {
|
||||||
|
@ -196,7 +193,7 @@ class CompactBlockBatchDownloadOperation: ZcashOperation {
|
||||||
while !isCancelled && currentHeight <= targetHeight {
|
while !isCancelled && currentHeight <= targetHeight {
|
||||||
var retries = 0
|
var retries = 0
|
||||||
var success = true
|
var success = true
|
||||||
var localError: Error? = nil
|
var localError: Error?
|
||||||
|
|
||||||
let range = nextRange(currentHeight: currentHeight, targetHeight: targetHeight)
|
let range = nextRange(currentHeight: currentHeight, targetHeight: targetHeight)
|
||||||
|
|
||||||
|
@ -205,18 +202,25 @@ class CompactBlockBatchDownloadOperation: ZcashOperation {
|
||||||
let blocks = try service.blockRange(range)
|
let blocks = try service.blockRange(range)
|
||||||
try storage.insert(blocks)
|
try storage.insert(blocks)
|
||||||
success = true
|
success = true
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
success = false
|
success = false
|
||||||
localError = error
|
localError = error
|
||||||
retries = retries + 1
|
retries += 1
|
||||||
}
|
}
|
||||||
} while !isCancelled && !success && retries < maxRetries
|
} while !isCancelled && !success && retries < maxRetries
|
||||||
if retries >= maxRetries {
|
if retries >= maxRetries {
|
||||||
throw CompactBlockBatchDownloadOperationError.batchDownloadFailed(range: range, error: localError)
|
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
|
currentHeight = range.upperBound + 1
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
@ -56,25 +56,27 @@ class CompactBlockEnhancementOperation: ZcashOperation {
|
||||||
// fetch transactions
|
// fetch transactions
|
||||||
|
|
||||||
do {
|
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)")
|
LoggerProxy.debug("no transactions detected on range: \(range.printRange)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for index in 0 ..< transactions.count {
|
for index in 0 ..< transactions.count {
|
||||||
let tx = transactions[index]
|
let transaction = transactions[index]
|
||||||
|
|
||||||
var retry = true
|
var retry = true
|
||||||
while retry && self.retries < maxRetries {
|
while retry && self.retries < maxRetries {
|
||||||
do {
|
do {
|
||||||
let confirmedTx = try enhance(transaction: tx)
|
let confirmedTx = try enhance(transaction: transaction)
|
||||||
retry = false
|
retry = false
|
||||||
self.reportProgress(totalTransactions: transactions.count,
|
self.reportProgress(
|
||||||
enhanced: index + 1,
|
totalTransactions: transactions.count,
|
||||||
txEnhanced: confirmedTx)
|
enhanced: index + 1,
|
||||||
|
txEnhanced: confirmedTx
|
||||||
|
)
|
||||||
} catch {
|
} catch {
|
||||||
self.retries = self.retries + 1
|
self.retries += 1
|
||||||
LoggerProxy.error("could not enhance txId \(tx.transactionId.toHexStringTxId()) - Error: \(error)")
|
LoggerProxy.error("could not enhance txId \(transaction.transactionId.toHexStringTxId()) - Error: \(error)")
|
||||||
if retries > maxRetries {
|
if retries > maxRetries {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
@ -94,34 +96,42 @@ class CompactBlockEnhancementOperation: ZcashOperation {
|
||||||
}
|
}
|
||||||
|
|
||||||
func reportProgress(totalTransactions: Int, enhanced: Int, txEnhanced: ConfirmedTransactionEntity) {
|
func reportProgress(totalTransactions: Int, enhanced: Int, txEnhanced: ConfirmedTransactionEntity) {
|
||||||
self.progressDelegate?.progressUpdated(.enhance(
|
self.progressDelegate?.progressUpdated(
|
||||||
EnhancementStreamProgress(
|
.enhance(
|
||||||
totalTransactions: totalTransactions,
|
EnhancementStreamProgress(
|
||||||
enhancedTransactions: enhanced,
|
totalTransactions: totalTransactions,
|
||||||
lastFoundTransaction: txEnhanced,
|
enhancedTransactions: enhanced,
|
||||||
range: self.range.compactBlockRange)))
|
lastFoundTransaction: txEnhanced,
|
||||||
|
range: self.range.compactBlockRange
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func enhance(transaction: TransactionEntity) throws -> ConfirmedTransactionEntity {
|
func enhance(transaction: TransactionEntity) throws -> ConfirmedTransactionEntity {
|
||||||
LoggerProxy.debug("Zoom.... Enhance... Tx: \(transaction.transactionId.toHexStringTxId())")
|
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 {
|
guard let rawBytes = transaction.raw?.bytes else {
|
||||||
let error = EnhancementError.noRawData(message: "Critical Error: transaction id: \(tx.transactionId.toHexStringTxId()) has no data")
|
let error = EnhancementError.noRawData(
|
||||||
|
message: "Critical Error: transaction id: \(transaction.transactionId.toHexStringTxId()) has no data"
|
||||||
|
)
|
||||||
LoggerProxy.error("\(error)")
|
LoggerProxy.error("\(error)")
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let minedHeight = tx.minedHeight else {
|
guard let minedHeight = transaction.minedHeight else {
|
||||||
let error = EnhancementError.noRawData(message: "Critical Error - Attempt to decrypt and store an unmined transaction. Id: \(tx.transactionId.toHexStringTxId()) ")
|
let error = EnhancementError.noRawData(
|
||||||
|
message: "Critical Error - Attempt to decrypt and store an unmined transaction. Id: \(transaction.transactionId.toHexStringTxId())"
|
||||||
|
)
|
||||||
LoggerProxy.error("\(error)")
|
LoggerProxy.error("\(error)")
|
||||||
throw 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() {
|
if let rustError = rustBackend.lastError() {
|
||||||
throw EnhancementError.decryptError(error: rustError)
|
throw EnhancementError.decryptError(error: rustError)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
// Created by Francisco Gindre on 18/09/2019.
|
// Created by Francisco Gindre on 18/09/2019.
|
||||||
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
||||||
//
|
//
|
||||||
|
// swiftlint:disable file_length type_body_length
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import GRPC
|
import GRPC
|
||||||
|
@ -34,7 +35,7 @@ public enum CompactBlockProcessorError: Error {
|
||||||
CompactBlockProcessor notification userInfo object keys.
|
CompactBlockProcessor notification userInfo object keys.
|
||||||
check Notification.Name extensions for more details.
|
check Notification.Name extensions for more details.
|
||||||
*/
|
*/
|
||||||
public struct CompactBlockProcessorNotificationKey {
|
public enum CompactBlockProcessorNotificationKey {
|
||||||
public static let progress = "CompactBlockProcessorNotificationKey.progress"
|
public static let progress = "CompactBlockProcessorNotificationKey.progress"
|
||||||
// public static let progressStartHeight = "CompactBlockProcessorNotificationKey.progressStartHeight"
|
// public static let progressStartHeight = "CompactBlockProcessorNotificationKey.progressStartHeight"
|
||||||
// public static let progressTargetHeight = "CompactBlockProcessorNotificationKey.progressTargetHeight"
|
// public static let progressTargetHeight = "CompactBlockProcessorNotificationKey.progressTargetHeight"
|
||||||
|
@ -63,11 +64,11 @@ public enum CompactBlockProgress {
|
||||||
|
|
||||||
public var progress: Float {
|
public var progress: Float {
|
||||||
switch self {
|
switch self {
|
||||||
case .download(let p),
|
case .download(let blockProgress),
|
||||||
.scan(let p):
|
.scan(let blockProgress):
|
||||||
return p.progress
|
return blockProgress.progress
|
||||||
case .enhance(let p):
|
case .enhance(let enhancementProgress):
|
||||||
return p.progress
|
return enhancementProgress.progress
|
||||||
default:
|
default:
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -75,18 +76,19 @@ public enum CompactBlockProgress {
|
||||||
|
|
||||||
public var progressHeight: BlockHeight? {
|
public var progressHeight: BlockHeight? {
|
||||||
switch self {
|
switch self {
|
||||||
case .download(let p),
|
case .download(let blockProgress),
|
||||||
.scan(let p):
|
.scan(let blockProgress):
|
||||||
return p.progressHeight
|
return blockProgress.progressHeight
|
||||||
case .enhance(let p):
|
case .enhance(let enhancementProgress):
|
||||||
return p.lastFoundTransaction?.minedHeight
|
return enhancementProgress.lastFoundTransaction?.minedHeight
|
||||||
default:
|
default:
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var blockDate: Date? {
|
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 Date(timeIntervalSince1970: time)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -94,8 +96,8 @@ public enum CompactBlockProgress {
|
||||||
|
|
||||||
public var targetHeight: BlockHeight? {
|
public var targetHeight: BlockHeight? {
|
||||||
switch self {
|
switch self {
|
||||||
case .download(let p), .scan(let p):
|
case .download(let blockProgress), .scan(let blockProgress):
|
||||||
return p.targetHeight
|
return blockProgress.targetHeight
|
||||||
default:
|
default:
|
||||||
return nil
|
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`
|
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")
|
static let blockProcessorConnectivityStateChanged = Notification.Name("CompactBlockProcessorConnectivityStateChanged")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -219,14 +220,14 @@ public class CompactBlockProcessor {
|
||||||
public struct Configuration {
|
public struct Configuration {
|
||||||
public var cacheDb: URL
|
public var cacheDb: URL
|
||||||
public var dataDb: URL
|
public var dataDb: URL
|
||||||
public var downloadBatchSize = ZcashSDK.DEFAULT_BATCH_SIZE
|
public var downloadBatchSize = ZcashSDK.DefaultBatchSize
|
||||||
public var blockPollInterval: TimeInterval {
|
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 retries = ZcashSDK.defaultRetries
|
||||||
public var maxBackoffInterval = ZcashSDK.DEFAULT_MAX_BACKOFF_INTERVAL
|
public var maxBackoffInterval = ZcashSDK.defaultMaxBackOffInterval
|
||||||
public var rewindDistance = ZcashSDK.DEFAULT_REWIND_DISTANCE
|
public var rewindDistance = ZcashSDK.defaultRewindDistance
|
||||||
public var walletBirthday: BlockHeight
|
public var walletBirthday: BlockHeight
|
||||||
private(set) var network: ZcashNetwork
|
private(set) var network: ZcashNetwork
|
||||||
private(set) var saplingActivation: BlockHeight
|
private(set) var saplingActivation: BlockHeight
|
||||||
|
@ -257,7 +258,7 @@ public class CompactBlockProcessor {
|
||||||
self.cacheDb = cacheDb
|
self.cacheDb = cacheDb
|
||||||
self.dataDb = dataDb
|
self.dataDb = dataDb
|
||||||
self.walletBirthday = walletBirthday
|
self.walletBirthday = walletBirthday
|
||||||
self.saplingActivation = network.constants.SAPLING_ACTIVATION_HEIGHT
|
self.saplingActivation = network.constants.saplingActivationHeight
|
||||||
self.network = network
|
self.network = network
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,12 +323,12 @@ public class CompactBlockProcessor {
|
||||||
self.stop()
|
self.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private var queue: OperationQueue = {
|
private var operationQueue: OperationQueue = {
|
||||||
let q = OperationQueue()
|
let queue = OperationQueue()
|
||||||
q.name = "CompactBlockProcessorQueue"
|
queue.name = "CompactBlockProcessorQueue"
|
||||||
q.maxConcurrentOperationCount = 1
|
queue.maxConcurrentOperationCount = 1
|
||||||
return q
|
return queue
|
||||||
} ()
|
}()
|
||||||
|
|
||||||
private var retryAttempts: Int = 0
|
private var retryAttempts: Int = 0
|
||||||
private var backoffTimer: Timer?
|
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
|
- Throws CompactBlockProcessorError.invalidConfiguration if block height is invalid or if processor is already started
|
||||||
*/
|
*/
|
||||||
func setStartHeight(_ startHeight: BlockHeight) throws {
|
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
|
throw CompactBlockProcessorError.invalidConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,16 +368,21 @@ public class CompactBlockProcessor {
|
||||||
- downloader: an instance that complies to CompactBlockDownloading protocol
|
- downloader: an instance that complies to CompactBlockDownloading protocol
|
||||||
- backend: a class that complies to ZcashRustBackendWelding
|
- backend: a class that complies to ZcashRustBackendWelding
|
||||||
*/
|
*/
|
||||||
convenience init(service: LightWalletService,
|
convenience init(
|
||||||
storage: CompactBlockStorage,
|
service: LightWalletService,
|
||||||
backend: ZcashRustBackendWelding.Type,
|
storage: CompactBlockStorage,
|
||||||
config: Configuration) {
|
backend: ZcashRustBackendWelding.Type,
|
||||||
self.init(service: service,
|
config: Configuration
|
||||||
storage: storage,
|
) {
|
||||||
backend: backend,
|
self.init(
|
||||||
config: config,
|
service: service,
|
||||||
repository: TransactionRepositoryBuilder.build(dataDbURL: config.dataDb),
|
storage: storage,
|
||||||
accountRepository: AccountRepositoryBuilder.build(dataDbURL: config.dataDb, readOnly: true))
|
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
|
- initializer: an instance that complies to CompactBlockDownloading protocol
|
||||||
*/
|
*/
|
||||||
public convenience init(initializer: Initializer) {
|
public convenience init(initializer: Initializer) {
|
||||||
|
self.init(
|
||||||
self.init(service: initializer.lightWalletService,
|
service: initializer.lightWalletService,
|
||||||
storage: initializer.storage,
|
storage: initializer.storage,
|
||||||
backend: initializer.rustBackend,
|
backend: initializer.rustBackend,
|
||||||
config: Configuration(cacheDb: initializer.cacheDbURL,
|
config: Configuration(
|
||||||
dataDb: initializer.dataDbURL,
|
cacheDb: initializer.cacheDbURL,
|
||||||
walletBirthday: initializer.walletBirthday.height,
|
dataDb: initializer.dataDbURL,
|
||||||
network: initializer.network),
|
walletBirthday: initializer.walletBirthday.height,
|
||||||
repository: initializer.transactionRepository,
|
network: initializer.network
|
||||||
accountRepository: initializer.accountRepository)
|
),
|
||||||
|
repository: initializer.transactionRepository,
|
||||||
|
accountRepository: initializer.accountRepository)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal init(service: LightWalletService,
|
internal init(
|
||||||
storage: CompactBlockStorage,
|
service: LightWalletService,
|
||||||
backend: ZcashRustBackendWelding.Type,
|
storage: CompactBlockStorage,
|
||||||
config: Configuration,
|
backend: ZcashRustBackendWelding.Type,
|
||||||
repository: TransactionRepository,
|
config: Configuration,
|
||||||
accountRepository: AccountRepository) {
|
repository: TransactionRepository,
|
||||||
|
accountRepository: AccountRepository
|
||||||
|
) {
|
||||||
self.service = service
|
self.service = service
|
||||||
self.downloader = CompactBlockDownloader(service: service, storage: storage)
|
self.downloader = CompactBlockDownloader(service: service, storage: storage)
|
||||||
self.rustBackend = backend
|
self.rustBackend = backend
|
||||||
|
@ -414,7 +424,7 @@ public class CompactBlockProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
self.queue.cancelAllOperations()
|
self.operationQueue.cancelAllOperations()
|
||||||
}
|
}
|
||||||
|
|
||||||
var maxAttemptsReached: Bool {
|
var maxAttemptsReached: Bool {
|
||||||
|
@ -447,7 +457,6 @@ public class CompactBlockProcessor {
|
||||||
|
|
||||||
*/
|
*/
|
||||||
public func start(retry: Bool = false) throws {
|
public func start(retry: Bool = false) throws {
|
||||||
|
|
||||||
// TODO: check if this validation makes sense at all
|
// TODO: check if this validation makes sense at all
|
||||||
// try validateConfiguration()
|
// try validateConfiguration()
|
||||||
if retry {
|
if retry {
|
||||||
|
@ -456,9 +465,9 @@ public class CompactBlockProcessor {
|
||||||
self.backoffTimer?.invalidate()
|
self.backoffTimer?.invalidate()
|
||||||
self.backoffTimer = nil
|
self.backoffTimer = nil
|
||||||
}
|
}
|
||||||
guard !queue.isSuspended else {
|
guard !operationQueue.isSuspended else {
|
||||||
LoggerProxy.debug("restarting suspended queue")
|
LoggerProxy.debug("restarting suspended queue")
|
||||||
queue.isSuspended = false
|
operationQueue.isSuspended = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,7 +496,6 @@ public class CompactBlockProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateServer(completionBlock: @escaping (() -> Void)) {
|
func validateServer(completionBlock: @escaping (() -> Void)) {
|
||||||
|
|
||||||
self.service.getInfo(result: { [weak self] result in
|
self.service.getInfo(result: { [weak self] result in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
@ -496,10 +504,12 @@ public class CompactBlockProcessor {
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
do {
|
do {
|
||||||
try Self.validateServerInfo(info,
|
try Self.validateServerInfo(
|
||||||
saplingActivation: self.config.saplingActivation,
|
info,
|
||||||
localNetwork: self.config.network,
|
saplingActivation: self.config.saplingActivation,
|
||||||
rustBackend: self.rustBackend)
|
localNetwork: self.config.network,
|
||||||
|
rustBackend: self.rustBackend
|
||||||
|
)
|
||||||
completionBlock()
|
completionBlock()
|
||||||
} catch {
|
} catch {
|
||||||
self.severeFailure(error)
|
self.severeFailure(error)
|
||||||
|
@ -511,14 +521,18 @@ public class CompactBlockProcessor {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static func validateServerInfo(_ info: LightWalletdInfo,
|
static func validateServerInfo(
|
||||||
saplingActivation: BlockHeight,
|
_ info: LightWalletdInfo,
|
||||||
localNetwork: ZcashNetwork,
|
saplingActivation: BlockHeight,
|
||||||
rustBackend: ZcashRustBackendWelding.Type) throws {
|
localNetwork: ZcashNetwork,
|
||||||
|
rustBackend: ZcashRustBackendWelding.Type) throws {
|
||||||
|
|
||||||
// check network types
|
// check network types
|
||||||
guard let remoteNetworkType = NetworkType.forChainName(info.chainName) else {
|
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 {
|
guard remoteNetworkType == localNetwork.networkType else {
|
||||||
|
@ -539,8 +553,7 @@ public class CompactBlockProcessor {
|
||||||
|
|
||||||
guard remoteBranchID == localBranch else {
|
guard remoteBranchID == localBranch else {
|
||||||
throw CompactBlockProcessorError.wrongConsensusBranchId(expectedLocally: localBranch, found: remoteBranchID)
|
throw CompactBlockProcessorError.wrongConsensusBranchId(expectedLocally: localBranch, found: remoteBranchID)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -553,9 +566,9 @@ public class CompactBlockProcessor {
|
||||||
self.backoffTimer?.invalidate()
|
self.backoffTimer?.invalidate()
|
||||||
self.backoffTimer = nil
|
self.backoffTimer = nil
|
||||||
if cancelTasks {
|
if cancelTasks {
|
||||||
queue.cancelAllOperations()
|
operationQueue.cancelAllOperations()
|
||||||
} else {
|
} else {
|
||||||
self.queue.isSuspended = true
|
self.operationQueue.isSuspended = true
|
||||||
}
|
}
|
||||||
|
|
||||||
self.retryAttempts = 0
|
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
|
let validateScanningAdapterOperation = BlockOperation { [weak scanBlocksOperation, weak validateChainOperation] in
|
||||||
scanBlocksOperation?.error = validateChainOperation?.error
|
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 {
|
guard !cancelled else {
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
self?.state = .stopped
|
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
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.processingError = error
|
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 = {
|
enhanceOperation.startedHandler = {
|
||||||
LoggerProxy.debug("Started Enhancing range: \(range)")
|
LoggerProxy.debug("Started Enhancing range: \(range)")
|
||||||
|
@ -743,18 +771,18 @@ public class CompactBlockProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enhanceOperation.txFoundHandler = { [weak self] (txs,range) in
|
enhanceOperation.txFoundHandler = { [weak self] txs, range in
|
||||||
self?.notifyTransactions(txs,in: range)
|
self?.notifyTransactions(txs, in: range)
|
||||||
}
|
}
|
||||||
|
|
||||||
enhanceOperation.completionHandler = { (finished, cancelled) in
|
enhanceOperation.completionHandler = { finished, cancelled in
|
||||||
guard !cancelled else {
|
guard !cancelled else {
|
||||||
LoggerProxy.debug("Warning: enhance operation on range \(range) cancelled")
|
LoggerProxy.debug("Warning: enhance operation on range \(range) cancelled")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enhanceOperation.errorHandler = { [weak self] (error) in
|
enhanceOperation.errorHandler = { [weak self] error in
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
@ -767,7 +795,14 @@ public class CompactBlockProcessor {
|
||||||
enhanceOperation?.error = scanBlocksOperation?.error
|
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
|
fetchOperation.startedHandler = { [weak self] in
|
||||||
DispatchQueue.main.async { [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 {
|
guard !cancelled else {
|
||||||
LoggerProxy.debug("Warning: fetch operation on range \(range) cancelled")
|
LoggerProxy.debug("Warning: fetch operation on range \(range) cancelled")
|
||||||
return
|
return
|
||||||
|
@ -784,7 +819,7 @@ public class CompactBlockProcessor {
|
||||||
self?.processBatchFinished(range: range)
|
self?.processBatchFinished(range: range)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fetchOperation.errorHandler = { [weak self] (error) in
|
fetchOperation.errorHandler = { [weak self] error in
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
@ -809,7 +844,7 @@ public class CompactBlockProcessor {
|
||||||
enhanceFetchAdapterOperation.addDependency(enhanceOperation)
|
enhanceFetchAdapterOperation.addDependency(enhanceOperation)
|
||||||
fetchOperation.addDependency(enhanceFetchAdapterOperation)
|
fetchOperation.addDependency(enhanceFetchAdapterOperation)
|
||||||
|
|
||||||
queue.addOperations([downloadBlockOperation,
|
operationQueue.addOperations([downloadBlockOperation,
|
||||||
downloadValidateAdapterOperation,
|
downloadValidateAdapterOperation,
|
||||||
validateChainOperation,
|
validateChainOperation,
|
||||||
validateScanningAdapterOperation,
|
validateScanningAdapterOperation,
|
||||||
|
@ -853,15 +888,19 @@ public class CompactBlockProcessor {
|
||||||
private func validationFailed(at height: BlockHeight) {
|
private func validationFailed(at height: BlockHeight) {
|
||||||
|
|
||||||
// cancel all Tasks
|
// cancel all Tasks
|
||||||
queue.cancelAllOperations()
|
operationQueue.cancelAllOperations()
|
||||||
|
|
||||||
// register latest failure
|
// register latest failure
|
||||||
self.lastChainValidationFailure = height
|
self.lastChainValidationFailure = height
|
||||||
self.consecutiveChainValidationErrors = self.consecutiveChainValidationErrors + 1
|
self.consecutiveChainValidationErrors += 1
|
||||||
|
|
||||||
// rewind
|
// 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 {
|
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)"))
|
fail(rustBackend.lastError() ?? RustWeldingError.genericError(message: "unknown error rewinding to height \(height)"))
|
||||||
return
|
return
|
||||||
|
@ -871,7 +910,13 @@ public class CompactBlockProcessor {
|
||||||
try downloader.rewind(to: rewindHeight)
|
try downloader.rewind(to: rewindHeight)
|
||||||
|
|
||||||
// notify reorg
|
// 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
|
// process next batch
|
||||||
self.nextBatch()
|
self.nextBatch()
|
||||||
|
@ -880,13 +925,16 @@ public class CompactBlockProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func determineLowerBound(errorHeight: Int, consecutiveErrors: Int, walletBirthday: BlockHeight) -> BlockHeight {
|
func determineLowerBound(
|
||||||
let offset = min(ZcashSDK.MAX_REORG_SIZE, ZcashSDK.DEFAULT_REWIND_DISTANCE * (consecutiveErrors + 1))
|
errorHeight: Int,
|
||||||
return max(errorHeight - offset, walletBirthday - ZcashSDK.MAX_REORG_SIZE)
|
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) {
|
private func processBatchFinished(range: CompactBlockRange) {
|
||||||
|
|
||||||
guard processingError == nil else {
|
guard processingError == nil else {
|
||||||
retryProcessing(range: range)
|
retryProcessing(range: range)
|
||||||
return
|
return
|
||||||
|
@ -908,9 +956,10 @@ public class CompactBlockProcessor {
|
||||||
name: Notification.Name.blockProcessorFinished,
|
name: Notification.Name.blockProcessorFinished,
|
||||||
object: self,
|
object: self,
|
||||||
userInfo: [
|
userInfo: [
|
||||||
CompactBlockProcessorNotificationKey.latestScannedBlockHeight : height,
|
CompactBlockProcessorNotificationKey.latestScannedBlockHeight: height,
|
||||||
CompactBlockProcessorNotificationKey.foundBlocks : self.foundBlocks
|
CompactBlockProcessorNotificationKey.foundBlocks: self.foundBlocks
|
||||||
])
|
]
|
||||||
|
)
|
||||||
self.state = .synced
|
self.state = .synced
|
||||||
setTimer()
|
setTimer()
|
||||||
}
|
}
|
||||||
|
@ -923,13 +972,15 @@ public class CompactBlockProcessor {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if self.shouldStart {
|
if self.shouldStart {
|
||||||
LoggerProxy.debug("""
|
LoggerProxy.debug(
|
||||||
Timer triggered: Starting compact Block processor!.
|
"""
|
||||||
Processor State: \(self.state)
|
Timer triggered: Starting compact Block processor!.
|
||||||
latestHeight: \(self.latestBlockHeight)
|
Processor State: \(self.state)
|
||||||
attempts: \(self.retryAttempts)
|
latestHeight: \(self.latestBlockHeight)
|
||||||
lowerbound: \(String(describing: self.lowerBoundHeight))
|
attempts: \(self.retryAttempts)
|
||||||
""")
|
lowerbound: \(String(describing: self.lowerBoundHeight))
|
||||||
|
"""
|
||||||
|
)
|
||||||
try self.start()
|
try self.start()
|
||||||
} else if self.maxAttemptsReached {
|
} else if self.maxAttemptsReached {
|
||||||
self.fail(CompactBlockProcessorError.maxAttemptsReached(attempts: self.config.retries))
|
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 {
|
static func nextBatchBlockRange(latestHeight: BlockHeight, latestDownloadedHeight: BlockHeight, walletBirthday: BlockHeight) -> CompactBlockRange {
|
||||||
|
|
||||||
let lowerBound = latestDownloadedHeight <= walletBirthday ? walletBirthday : latestDownloadedHeight + 1
|
let lowerBound = latestDownloadedHeight <= walletBirthday ? walletBirthday : latestDownloadedHeight + 1
|
||||||
|
|
||||||
let upperBound = latestHeight
|
let upperBound = latestHeight
|
||||||
|
@ -952,10 +1002,9 @@ public class CompactBlockProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
func retryProcessing(range: CompactBlockRange) {
|
func retryProcessing(range: CompactBlockRange) {
|
||||||
|
operationQueue.cancelAllOperations()
|
||||||
queue.cancelAllOperations()
|
|
||||||
// update retries
|
// update retries
|
||||||
self.retryAttempts = self.retryAttempts + 1
|
self.retryAttempts += 1
|
||||||
self.processingError = nil
|
self.processingError = nil
|
||||||
guard self.retryAttempts < config.retries else {
|
guard self.retryAttempts < config.retries else {
|
||||||
self.notifyError(CompactBlockProcessorError.maxAttemptsReached(attempts: self.retryAttempts))
|
self.notifyError(CompactBlockProcessorError.maxAttemptsReached(attempts: self.retryAttempts))
|
||||||
|
@ -972,25 +1021,23 @@ public class CompactBlockProcessor {
|
||||||
} catch {
|
} catch {
|
||||||
self.fail(error)
|
self.fail(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func severeFailure(_ error: Error) {
|
func severeFailure(_ error: Error) {
|
||||||
queue.cancelAllOperations()
|
operationQueue.cancelAllOperations()
|
||||||
LoggerProxy.error("show stoppper failure: \(error)")
|
LoggerProxy.error("show stoppper failure: \(error)")
|
||||||
self.backoffTimer?.invalidate()
|
self.backoffTimer?.invalidate()
|
||||||
self.retryAttempts = config.retries
|
self.retryAttempts = config.retries
|
||||||
self.processingError = error
|
self.processingError = error
|
||||||
self.state = .error(error)
|
self.state = .error(error)
|
||||||
self.notifyError(error)
|
self.notifyError(error)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func fail(_ error: Error) {
|
func fail(_ error: Error) {
|
||||||
// todo specify: failure
|
// todo specify: failure
|
||||||
LoggerProxy.error("\(error)")
|
LoggerProxy.error("\(error)")
|
||||||
queue.cancelAllOperations()
|
operationQueue.cancelAllOperations()
|
||||||
self.retryAttempts = self.retryAttempts + 1
|
self.retryAttempts += 1
|
||||||
self.processingError = error
|
self.processingError = error
|
||||||
switch self.state {
|
switch self.state {
|
||||||
case .error:
|
case .error:
|
||||||
|
@ -1002,7 +1049,6 @@ public class CompactBlockProcessor {
|
||||||
guard self.maxAttemptsReached else { return }
|
guard self.maxAttemptsReached else { return }
|
||||||
// don't set a new timer if there are no more attempts.
|
// don't set a new timer if there are no more attempts.
|
||||||
self.setTimer()
|
self.setTimer()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func transitionState(from oldValue: State, to newValue: State) {
|
private func transitionState(from oldValue: State, to newValue: State) {
|
||||||
|
@ -1125,7 +1171,7 @@ extension CompactBlockProcessor {
|
||||||
guard let account = try? accountRepository.findBy(account: accountIndex) else {
|
guard let account = try? accountRepository.findBy(account: accountIndex) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return UnifiedAddressShim(__account: account)
|
return UnifiedAddressShim(account: account)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getShieldedAddress(accountIndex: Int) -> SaplingShieldedAddress? {
|
public func getShieldedAddress(accountIndex: Int) -> SaplingShieldedAddress? {
|
||||||
|
@ -1144,38 +1190,40 @@ extension CompactBlockProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate struct UnifiedAddressShim {
|
private struct UnifiedAddressShim {
|
||||||
let __account: AccountEntity
|
let account: AccountEntity
|
||||||
}
|
}
|
||||||
|
|
||||||
extension UnifiedAddressShim: UnifiedAddress {
|
extension UnifiedAddressShim: UnifiedAddress {
|
||||||
var tAddress: TransparentAddress {
|
var tAddress: TransparentAddress {
|
||||||
get {
|
get {
|
||||||
__account.transparentAddress
|
account.transparentAddress
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var zAddress: SaplingShieldedAddress {
|
var zAddress: SaplingShieldedAddress {
|
||||||
get {
|
get {
|
||||||
__account.address
|
account.address
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension CompactBlockProcessor {
|
extension CompactBlockProcessor {
|
||||||
|
|
||||||
func refreshUTXOs(tAddress: String, startHeight: BlockHeight, result: @escaping (Result<RefreshedUTXOs,Error>) -> Void) {
|
func refreshUTXOs(tAddress: String, startHeight: BlockHeight, result: @escaping (Result<RefreshedUTXOs,Error>) -> Void) {
|
||||||
let dataDb = self.config.dataDb
|
let dataDb = self.config.dataDb
|
||||||
self.downloader.fetchUnspentTransactionOutputs(tAddress: tAddress, startHeight: startHeight) { [weak self](r) in
|
self.downloader.fetchUnspentTransactionOutputs(tAddress: tAddress, startHeight: startHeight) { [weak self](r) in
|
||||||
|
|
||||||
switch r {
|
switch r {
|
||||||
case .success(let utxos):
|
case .success(let utxos):
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self?.queue.addOperation { [self] in
|
self?.operationQueue.addOperation { [self] in
|
||||||
|
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
do {
|
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")))
|
result(.failure(CompactBlockProcessorError.generalError(message: "attempted to clear utxos but -1 was returned")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1204,7 +1252,8 @@ extension CompactBlockProcessor {
|
||||||
script: utxo.script.bytes,
|
script: utxo.script.bytes,
|
||||||
value: Int64(utxo.valueZat),
|
value: Int64(utxo.valueZat),
|
||||||
height: utxo.height,
|
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 {
|
} catch {
|
||||||
LoggerProxy.info("failed to put utxo - error: \(error)")
|
LoggerProxy.info("failed to put utxo - error: \(error)")
|
||||||
skipped.append(utxo)
|
skipped.append(utxo)
|
||||||
|
@ -1239,12 +1288,15 @@ extension CompactBlockProcessorError: LocalizedError {
|
||||||
case .missingDbPath(let path):
|
case .missingDbPath(let path):
|
||||||
return "CompactBlockProcessor was set up with path \(path) but thath location couldn't be reached"
|
return "CompactBlockProcessor was set up with path \(path) but thath location couldn't be reached"
|
||||||
case .networkMismatch(let expected, let found):
|
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"
|
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):
|
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?"
|
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):
|
case .unspecifiedError(let underlyingError):
|
||||||
return "Unspecified error caused by this underlying error: \(underlyingError)"
|
return "Unspecified error caused by this underlying error: \(underlyingError)"
|
||||||
case .wrongConsensusBranchId(let expectedLocally, let found):
|
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."
|
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 {
|
extension CompactBlockProcessor {
|
||||||
|
enum NextStateHelper {
|
||||||
class NextStateHelper {
|
static func nextState(
|
||||||
|
service: LightWalletService,
|
||||||
static func nextState(service: LightWalletService,
|
downloader: CompactBlockDownloading,
|
||||||
downloader: CompactBlockDownloading,
|
config: Configuration,
|
||||||
config: Configuration,
|
rustBackend: ZcashRustBackendWelding.Type,
|
||||||
rustBackend: ZcashRustBackendWelding.Type,
|
queue: DispatchQueue?,
|
||||||
queue: DispatchQueue?,
|
result: @escaping (Result<FigureNextBatchOperation.NextState, Error>) -> Void
|
||||||
result: @escaping (Result<FigureNextBatchOperation.NextState, Error>) -> Void) {
|
) {
|
||||||
|
|
||||||
let dispatchQueue = queue ?? DispatchQueue.global(qos: .userInitiated)
|
let dispatchQueue = queue ?? DispatchQueue.global(qos: .userInitiated)
|
||||||
|
|
||||||
dispatchQueue.async {
|
dispatchQueue.async {
|
||||||
do {
|
do {
|
||||||
let r = try self.nextState(service: service,
|
let r = try self.nextState(
|
||||||
downloader: downloader,
|
service: service,
|
||||||
config: config,
|
downloader: downloader,
|
||||||
rustBackend: rustBackend)
|
config: config,
|
||||||
|
rustBackend: rustBackend)
|
||||||
result(.success(r))
|
result(.success(r))
|
||||||
} catch {
|
} catch {
|
||||||
result(.failure(error))
|
result(.failure(error))
|
||||||
|
@ -1311,28 +1363,34 @@ extension CompactBlockProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func nextState(service: LightWalletService,
|
static func nextState(
|
||||||
downloader: CompactBlockDownloading,
|
service: LightWalletService,
|
||||||
config: Configuration,
|
downloader: CompactBlockDownloading,
|
||||||
rustBackend: ZcashRustBackendWelding.Type) throws -> FigureNextBatchOperation.NextState {
|
config: Configuration,
|
||||||
|
rustBackend: ZcashRustBackendWelding.Type
|
||||||
|
) throws -> FigureNextBatchOperation.NextState {
|
||||||
let info = try service.getInfo()
|
let info = try service.getInfo()
|
||||||
|
|
||||||
try CompactBlockProcessor.validateServerInfo(info, saplingActivation: config.saplingActivation, localNetwork: config.network, rustBackend: rustBackend)
|
try CompactBlockProcessor.validateServerInfo(info, saplingActivation: config.saplingActivation, localNetwork: config.network, rustBackend: rustBackend)
|
||||||
|
|
||||||
// get latest block height
|
// 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()
|
let latestBlockheight = try service.latestBlockHeight()
|
||||||
|
|
||||||
if latestDownloadedBlockHeight < 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 {
|
} else if latestBlockheight == latestDownloadedBlockHeight {
|
||||||
return .finishProcessing(height: latestBlockheight)
|
return .finishProcessing(height: latestBlockheight)
|
||||||
}
|
}
|
||||||
|
|
||||||
return .wait(latestHeight: latestBlockheight, latestDownloadHeight: latestBlockheight)
|
return .wait(latestHeight: latestBlockheight, latestDownloadHeight: latestBlockheight)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,10 +169,12 @@ class CompactBlockBatchScanningOperation: ZcashOperation {
|
||||||
}
|
}
|
||||||
let previousScannedHeight = lastScannedHeight
|
let previousScannedHeight = lastScannedHeight
|
||||||
let scanStartTime = Date()
|
let scanStartTime = Date()
|
||||||
guard self.rustBackend.scanBlocks(dbCache: self.cacheDb,
|
guard self.rustBackend.scanBlocks(
|
||||||
dbData: self.dataDb,
|
dbCache: self.cacheDb,
|
||||||
limit: batchSize,
|
dbData: self.dataDb,
|
||||||
networkType: network) else {
|
limit: batchSize,
|
||||||
|
networkType: network
|
||||||
|
) else {
|
||||||
self.scanFailed(self.rustBackend.lastError() ?? ZcashOperationError.unknown)
|
self.scanFailed(self.rustBackend.lastError() ?? ZcashOperationError.unknown)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -184,12 +186,18 @@ class CompactBlockBatchScanningOperation: ZcashOperation {
|
||||||
if scannedNewBlocks {
|
if scannedNewBlocks {
|
||||||
let progress = BlockProgress(startHeight: scanStartHeight, targetHeight: targetScanHeight, progressHeight: lastScannedHeight)
|
let progress = BlockProgress(startHeight: scanStartHeight, targetHeight: targetScanHeight, progressHeight: lastScannedHeight)
|
||||||
progressDelegate?.progressUpdated(.scan(progress))
|
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")
|
LoggerProxy.debug("Scanned \(lastScannedHeight - previousScannedHeight) blocks in \(scanFinishTime.timeIntervalSinceReferenceDate - scanStartTime.timeIntervalSinceReferenceDate) seconds")
|
||||||
}
|
}
|
||||||
|
|
||||||
} while !self.isCancelled && scannedNewBlocks && lastScannedHeight < targetScanHeight
|
} while !self.isCancelled && scannedNewBlocks && lastScannedHeight < targetScanHeight
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
scanFailed(error)
|
scanFailed(error)
|
||||||
|
|
|
@ -51,8 +51,8 @@ class ZcashOperation: Operation {
|
||||||
self.cancel()
|
self.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
if let e = error {
|
if let error = error {
|
||||||
self.error = e
|
self.error = error
|
||||||
}
|
}
|
||||||
LoggerProxy.debug("\(self) failed")
|
LoggerProxy.debug("\(self) failed")
|
||||||
|
|
||||||
|
@ -61,9 +61,8 @@ class ZcashOperation: Operation {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.handlerDispatchQueue.async { [weak self] in
|
self.handlerDispatchQueue.async { [weak self] in
|
||||||
let e = error ?? (self?.error ?? ZcashOperationError.unknown)
|
let error = error ?? (self?.error ?? ZcashOperationError.unknown)
|
||||||
errorHandler(e)
|
errorHandler(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//
|
//
|
||||||
// Created by Francisco Gindre on 7/28/21.
|
// Created by Francisco Gindre on 7/28/21.
|
||||||
//
|
//
|
||||||
|
// swiftlint:disable function_body_length line_length cyclomatic_complexity
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension WalletBirthday {
|
extension WalletBirthday {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//
|
//
|
||||||
// Created by Francisco Gindre on 7/28/21.
|
// Created by Francisco Gindre on 7/28/21.
|
||||||
//
|
//
|
||||||
|
// swiftlint:disable all
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension WalletBirthday {
|
extension WalletBirthday {
|
||||||
|
|
|
@ -67,146 +67,142 @@ public class ZcashSDK {
|
||||||
/**
|
/**
|
||||||
The number of zatoshi that equal 1 ZEC.
|
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.
|
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
|
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.
|
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
|
// Defaults
|
||||||
//
|
//
|
||||||
/**
|
/**
|
||||||
Default size of batches of blocks to request from the compact block service.
|
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
|
Default amount of time, in in seconds, to poll for new blocks. Typically, this should be about half the average
|
||||||
block time.
|
block time.
|
||||||
*/
|
*/
|
||||||
public static var DEFAULT_POLL_INTERVAL: TimeInterval = 20
|
public static var defaultPollInterval: TimeInterval = 20
|
||||||
/**
|
/**
|
||||||
Default attempts at retrying.
|
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
|
The default maximum amount of time to wait during retry backoff intervals. Failed loops will never wait longer than
|
||||||
this before retyring.
|
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
|
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.
|
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
|
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.
|
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
|
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
|
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
|
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
|
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
|
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.
|
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
|
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.
|
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 {
|
public protocol NetworkConstants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The height of the first sapling block. When it comes to shielded transactions, we do not need to consider any blocks
|
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.
|
prior to this height, at all.
|
||||||
*/
|
*/
|
||||||
static var SAPLING_ACTIVATION_HEIGHT: BlockHeight { get }
|
static var saplingActivationHeight: BlockHeight { get }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Default Name for LibRustZcash data.db
|
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
|
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
|
Default name for pending transactions db
|
||||||
*/
|
*/
|
||||||
static var DEFAULT_PENDING_DB_NAME: String { get }
|
static var defaultPendingDbName: String { get }
|
||||||
static var DEFAULT_DB_NAME_PREFIX: String { get }
|
static var defaultDbNamePrefix: String { get }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
fixed height where the SDK considers that the ZIP-321 was deployed. This is a workaround
|
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.
|
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
|
static func defaultFee(for height: BlockHeight) -> Int64
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension NetworkConstants {
|
public extension NetworkConstants {
|
||||||
|
|
||||||
static func defaultFee(for height: BlockHeight = BlockHeight.max) -> Int64 {
|
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
|
return 1_000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ZcashSDKMainnetConstants: NetworkConstants {
|
public class ZcashSDKMainnetConstants: NetworkConstants {
|
||||||
|
|
||||||
private init() {}
|
private init() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The height of the first sapling block. When it comes to shielded transactions, we do not need to consider any blocks
|
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.
|
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
|
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
|
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
|
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 {
|
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
|
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.
|
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
|
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
|
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
|
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
|
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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,40 +118,39 @@ class PendingTransactionSQLDAO: PendingTransactionRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
func createrTableIfNeeded() throws {
|
func createrTableIfNeeded() throws {
|
||||||
let statement = table.create(ifNotExists: true) { t in
|
let statement = table.create(ifNotExists: true) { createdTable in
|
||||||
t.column(TableColumns.id, primaryKey: .autoincrement)
|
createdTable.column(TableColumns.id, primaryKey: .autoincrement)
|
||||||
t.column(TableColumns.toAddress)
|
createdTable.column(TableColumns.toAddress)
|
||||||
t.column(TableColumns.accountIndex)
|
createdTable.column(TableColumns.accountIndex)
|
||||||
t.column(TableColumns.minedHeight)
|
createdTable.column(TableColumns.minedHeight)
|
||||||
t.column(TableColumns.expiryHeight)
|
createdTable.column(TableColumns.expiryHeight)
|
||||||
t.column(TableColumns.cancelled)
|
createdTable.column(TableColumns.cancelled)
|
||||||
t.column(TableColumns.encodeAttempts, defaultValue: 0)
|
createdTable.column(TableColumns.encodeAttempts, defaultValue: 0)
|
||||||
t.column(TableColumns.errorMessage)
|
createdTable.column(TableColumns.errorMessage)
|
||||||
t.column(TableColumns.errorCode)
|
createdTable.column(TableColumns.errorCode)
|
||||||
t.column(TableColumns.submitAttempts, defaultValue: 0)
|
createdTable.column(TableColumns.submitAttempts, defaultValue: 0)
|
||||||
t.column(TableColumns.createTime)
|
createdTable.column(TableColumns.createTime)
|
||||||
t.column(TableColumns.rawTransactionId)
|
createdTable.column(TableColumns.rawTransactionId)
|
||||||
t.column(TableColumns.value)
|
createdTable.column(TableColumns.value)
|
||||||
t.column(TableColumns.raw)
|
createdTable.column(TableColumns.raw)
|
||||||
t.column(TableColumns.memo)
|
createdTable.column(TableColumns.memo)
|
||||||
}
|
}
|
||||||
|
|
||||||
try dbProvider.connection().run(statement)
|
try dbProvider.connection().run(statement)
|
||||||
}
|
}
|
||||||
|
|
||||||
func create(_ transaction: PendingTransactionEntity) throws -> Int {
|
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(pendingTx)))
|
||||||
|
|
||||||
return try Int(dbProvider.connection().run(table.insert(tx)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(_ transaction: PendingTransactionEntity) throws {
|
func update(_ transaction: PendingTransactionEntity) throws {
|
||||||
let tx = transaction as? PendingTransaction ?? PendingTransaction.from(entity: transaction)
|
let pendingTx = transaction as? PendingTransaction ?? PendingTransaction.from(entity: transaction)
|
||||||
guard let id = tx.id else {
|
guard let id = pendingTx.id else {
|
||||||
throw StorageError.malformedEntity(fields: ["id"])
|
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 {
|
if updatedRows == 0 {
|
||||||
LoggerProxy.error("attempted to update pending transactions but no rows were updated")
|
LoggerProxy.error("attempted to update pending transactions but no rows were updated")
|
||||||
}
|
}
|
||||||
|
@ -166,17 +165,16 @@ class PendingTransactionSQLDAO: PendingTransactionRepository {
|
||||||
} catch {
|
} catch {
|
||||||
throw StorageError.updateFailed
|
throw StorageError.updateFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func cancel(_ transaction: PendingTransactionEntity) throws {
|
func cancel(_ transaction: PendingTransactionEntity) throws {
|
||||||
|
|
||||||
var tx = transaction as? PendingTransaction ?? PendingTransaction.from(entity: transaction)
|
var pendingTx = transaction as? PendingTransaction ?? PendingTransaction.from(entity: transaction)
|
||||||
tx.cancelled = 1
|
pendingTx.cancelled = 1
|
||||||
guard let id = tx.id else {
|
guard let txId = pendingTx.id else {
|
||||||
throw StorageError.malformedEntity(fields: ["id"])
|
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? {
|
func find(by id: Int) throws -> PendingTransactionEntity? {
|
||||||
|
@ -184,8 +182,8 @@ class PendingTransactionSQLDAO: PendingTransactionRepository {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
let tx: PendingTransaction = try row.decode()
|
let pendingTx: PendingTransaction = try row.decode()
|
||||||
return tx
|
return pendingTx
|
||||||
} catch {
|
} catch {
|
||||||
throw StorageError.operationFailed
|
throw StorageError.operationFailed
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,14 +60,13 @@ extension UnspentTransactionOutputEntity {
|
||||||
}
|
}
|
||||||
import SQLite
|
import SQLite
|
||||||
class UnspentTransactionOutputSQLDAO: UnspentTransactionOutputRepository {
|
class UnspentTransactionOutputSQLDAO: UnspentTransactionOutputRepository {
|
||||||
|
|
||||||
func store(utxos: [UnspentTransactionOutputEntity]) throws {
|
func store(utxos: [UnspentTransactionOutputEntity]) throws {
|
||||||
do {
|
do {
|
||||||
|
|
||||||
let db = try dbProvider.connection()
|
let db = try dbProvider.connection()
|
||||||
try dbProvider.connection().transaction {
|
try dbProvider.connection().transaction {
|
||||||
for utxo in utxos.map({ (u) -> UTXO in
|
for utxo in utxos.map({ (mappedUTXO) -> UTXO in
|
||||||
u as? UTXO ?? u.asUTXO()
|
mappedUTXO as? UTXO ?? mappedUTXO.asUTXO()
|
||||||
}) {
|
}) {
|
||||||
try db.run(table.insert(utxo))
|
try db.run(table.insert(utxo))
|
||||||
}
|
}
|
||||||
|
@ -153,7 +152,7 @@ class UnspentTransactionOutputSQLDAO: UnspentTransactionOutputRepository {
|
||||||
let verified = try dbProvider.connection().scalar(
|
let verified = try dbProvider.connection().scalar(
|
||||||
table.select(TableColumns.valueZat.sum)
|
table.select(TableColumns.valueZat.sum)
|
||||||
.filter(TableColumns.address == address)
|
.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(
|
let total = try dbProvider.connection().scalar(
|
||||||
table.select(TableColumns.valueZat.sum)
|
table.select(TableColumns.valueZat.sum)
|
||||||
.filter(TableColumns.address == address)) ?? 0
|
.filter(TableColumns.address == address)) ?? 0
|
||||||
|
|
|
@ -114,10 +114,10 @@ class AccountSQDAO: AccountRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(_ account: AccountEntity) throws {
|
func update(_ account: AccountEntity) throws {
|
||||||
guard let a = account as? Account else {
|
guard let acc = account as? Account else {
|
||||||
throw StorageError.updateFailed
|
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 {
|
if updatedRows == 0 {
|
||||||
LoggerProxy.error("attempted to update pending transactions but no rows were updated")
|
LoggerProxy.error("attempted to update pending transactions but no rows were updated")
|
||||||
throw StorageError.updateFailed
|
throw StorageError.updateFailed
|
||||||
|
@ -126,17 +126,16 @@ class AccountSQDAO: AccountRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
class CachingAccountDao: AccountRepository {
|
class CachingAccountDao: AccountRepository {
|
||||||
|
|
||||||
var dao: AccountRepository
|
var dao: AccountRepository
|
||||||
lazy var cache: [Int: AccountEntity] = {
|
lazy var cache: [Int: AccountEntity] = {
|
||||||
var c = [Int : AccountEntity]()
|
var accountCache = [Int: AccountEntity]()
|
||||||
guard let all = try? dao.getAll() else {
|
guard let all = try? dao.getAll() else {
|
||||||
return c
|
return accountCache
|
||||||
}
|
}
|
||||||
for a in all {
|
for acc in all {
|
||||||
c[a.account] = a
|
accountCache[acc.account] = acc
|
||||||
}
|
}
|
||||||
return c
|
return accountCache
|
||||||
}()
|
}()
|
||||||
|
|
||||||
init(dao: AccountRepository) {
|
init(dao: AccountRepository) {
|
||||||
|
@ -149,20 +148,20 @@ class CachingAccountDao: AccountRepository {
|
||||||
}
|
}
|
||||||
let all = try dao.getAll()
|
let all = try dao.getAll()
|
||||||
|
|
||||||
for a in all {
|
for acc in all {
|
||||||
cache[a.account] = a
|
cache[acc.account] = acc
|
||||||
}
|
}
|
||||||
return all
|
return all
|
||||||
}
|
}
|
||||||
|
|
||||||
func findBy(account: Int) throws -> AccountEntity? {
|
func findBy(account: Int) throws -> AccountEntity? {
|
||||||
if let a = cache[account] {
|
if let acc = cache[account] {
|
||||||
return a
|
return acc
|
||||||
}
|
}
|
||||||
|
|
||||||
let a = try dao.findBy(account: account)
|
let acc = try dao.findBy(account: account)
|
||||||
cache[account] = a
|
cache[account] = acc
|
||||||
return a
|
return acc
|
||||||
}
|
}
|
||||||
|
|
||||||
func findBy(address: String) throws -> AccountEntity? {
|
func findBy(address: String) throws -> AccountEntity? {
|
||||||
|
|
|
@ -153,7 +153,7 @@ public extension PendingTransactionEntity {
|
||||||
return false
|
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
|
TransactionEntity representation of this PendingTransactionEntity transaction
|
||||||
*/
|
*/
|
||||||
var transactionEntity: TransactionEntity {
|
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
|
TransactionEntity representation of this ConfirmedTransactionEntity transaction
|
||||||
*/
|
*/
|
||||||
var transactionEntity: TransactionEntity {
|
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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,11 +59,11 @@ public extension TransactionEntity {
|
||||||
|
|
||||||
func anchor(network: ZcashNetwork) -> BlockHeight? {
|
func anchor(network: ZcashNetwork) -> BlockHeight? {
|
||||||
if let minedHeight = self.minedHeight, minedHeight != -1 {
|
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 {
|
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
|
return nil
|
||||||
|
|
|
@ -10,11 +10,13 @@ import Foundation
|
||||||
extension String {
|
extension String {
|
||||||
func toTxIdString() -> String {
|
func toTxIdString() -> String {
|
||||||
var id = ""
|
var id = ""
|
||||||
self.reversed().pairs.map {
|
self.reversed().pairs
|
||||||
$0.reversed()
|
.map {
|
||||||
}.forEach { (reversed) in
|
$0.reversed()
|
||||||
id.append(String(reversed))
|
}
|
||||||
}
|
.forEach { (reversed) in
|
||||||
|
id.append(String(reversed))
|
||||||
|
}
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,8 +25,8 @@ extension Collection {
|
||||||
var pairs: [SubSequence] {
|
var pairs: [SubSequence] {
|
||||||
var startIndex = self.startIndex
|
var startIndex = self.startIndex
|
||||||
let count = self.count
|
let count = self.count
|
||||||
let n = count / 2 + count % 2
|
let halving = count / 2 + count % 2
|
||||||
return (0..<n).map { _ in
|
return (0..<halving).map { _ in
|
||||||
let endIndex = index(startIndex, offsetBy: 2, limitedBy: self.endIndex) ?? self.endIndex
|
let endIndex = index(startIndex, offsetBy: 2, limitedBy: self.endIndex) ?? self.endIndex
|
||||||
defer { startIndex = endIndex }
|
defer { startIndex = endIndex }
|
||||||
return self[startIndex..<endIndex]
|
return self[startIndex..<endIndex]
|
||||||
|
|
|
@ -195,7 +195,14 @@ public class Initializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
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 {
|
} catch RustWeldingError.dataDbNotEmpty {
|
||||||
// this is fine
|
// this is fine
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -212,14 +219,16 @@ public class Initializer {
|
||||||
}
|
}
|
||||||
} catch RustWeldingError.dataDbNotEmpty {
|
} catch RustWeldingError.dataDbNotEmpty {
|
||||||
// this is fine
|
// this is fine
|
||||||
}catch {
|
} catch {
|
||||||
throw rustBackend.lastError() ?? InitializerError.accountInitFailed
|
throw rustBackend.lastError() ?? InitializerError.accountInitFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
let migrationManager = MigrationManager(cacheDbConnection: SimpleConnectionProvider(path: cacheDbURL.path),
|
let migrationManager = MigrationManager(
|
||||||
dataDbConnection: SimpleConnectionProvider(path: dataDbURL.path),
|
cacheDbConnection: SimpleConnectionProvider(path: cacheDbURL.path),
|
||||||
pendingDbConnection: SimpleConnectionProvider(path: pendingDbURL.path),
|
dataDbConnection: SimpleConnectionProvider(path: dataDbURL.path),
|
||||||
networkType: self.network.networkType)
|
pendingDbConnection: SimpleConnectionProvider(path: pendingDbURL.path),
|
||||||
|
networkType: self.network.networkType
|
||||||
|
)
|
||||||
|
|
||||||
try migrationManager.performMigration(uvks: viewingKeys)
|
try migrationManager.performMigration(uvks: viewingKeys)
|
||||||
}
|
}
|
||||||
|
@ -257,7 +266,7 @@ public class Initializer {
|
||||||
checks if the provided address is a transparent zAddress
|
checks if the provided address is a transparent zAddress
|
||||||
*/
|
*/
|
||||||
public func isValidTransparentAddress(_ address: String) -> Bool {
|
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 {
|
func isSpendParameterPresent() -> Bool {
|
||||||
|
@ -268,7 +277,7 @@ public class Initializer {
|
||||||
FileManager.default.isReadableFile(atPath: self.outputParamsURL.path)
|
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 spendParameterPresent = isSpendParameterPresent()
|
||||||
let outputParameterPresent = isOutputParameterPresent()
|
let outputParameterPresent = isOutputParameterPresent()
|
||||||
|
|
||||||
|
@ -283,17 +292,17 @@ public class Initializer {
|
||||||
if !outputParameterPresent {
|
if !outputParameterPresent {
|
||||||
SaplingParameterDownloader.downloadOutputParameter(outputURL) { outputResult in
|
SaplingParameterDownloader.downloadOutputParameter(outputURL) { outputResult in
|
||||||
switch outputResult {
|
switch outputResult {
|
||||||
case .failure(let e):
|
case .failure(let error):
|
||||||
result(.failure(e))
|
result(.failure(error))
|
||||||
case .success:
|
case .success:
|
||||||
guard !spendParameterPresent else {
|
guard !spendParameterPresent else {
|
||||||
result(.success(false))
|
result(.success(false))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
SaplingParameterDownloader.downloadSpendParameter(spendURL) { (spendResult) in
|
SaplingParameterDownloader.downloadSpendParameter(spendURL) { spendResult in
|
||||||
switch spendResult {
|
switch spendResult {
|
||||||
case .failure(let e):
|
case .failure(let error):
|
||||||
result(.failure(e))
|
result(.failure(error))
|
||||||
case .success:
|
case .success:
|
||||||
result(.success(false))
|
result(.success(false))
|
||||||
}
|
}
|
||||||
|
@ -301,10 +310,10 @@ public class Initializer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if !spendParameterPresent {
|
} else if !spendParameterPresent {
|
||||||
SaplingParameterDownloader.downloadSpendParameter(spendURL) { (spendResult) in
|
SaplingParameterDownloader.downloadSpendParameter(spendURL) { spendResult in
|
||||||
switch spendResult {
|
switch spendResult {
|
||||||
case .failure(let e):
|
case .failure(let error):
|
||||||
result(.failure(e))
|
result(.failure(error))
|
||||||
case .success:
|
case .success:
|
||||||
result(.success(false))
|
result(.success(false))
|
||||||
}
|
}
|
||||||
|
@ -314,17 +323,21 @@ public class Initializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
class CompactBlockProcessorBuilder {
|
class CompactBlockProcessorBuilder {
|
||||||
static func buildProcessor(configuration: CompactBlockProcessor.Configuration,
|
static func buildProcessor(
|
||||||
service: LightWalletService,
|
configuration: CompactBlockProcessor.Configuration,
|
||||||
storage: CompactBlockStorage,
|
service: LightWalletService,
|
||||||
transactionRepository: TransactionRepository,
|
storage: CompactBlockStorage,
|
||||||
accountRepository: AccountRepository,
|
transactionRepository: TransactionRepository,
|
||||||
backend: ZcashRustBackendWelding.Type) -> CompactBlockProcessor {
|
accountRepository: AccountRepository,
|
||||||
return CompactBlockProcessor(service: service,
|
backend: ZcashRustBackendWelding.Type
|
||||||
storage: storage,
|
) -> CompactBlockProcessor {
|
||||||
backend: backend,
|
return CompactBlockProcessor(
|
||||||
config: configuration,
|
service: service,
|
||||||
repository: transactionRepository,
|
storage: storage,
|
||||||
accountRepository: accountRepository)
|
backend: backend,
|
||||||
|
config: configuration,
|
||||||
|
repository: transactionRepository,
|
||||||
|
accountRepository: accountRepository
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,9 @@ public struct DefaultResourceProvider: ResourceProvider {
|
||||||
let constants = network.constants
|
let constants = network.constants
|
||||||
do {
|
do {
|
||||||
let url = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
|
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 {
|
} 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
|
let constants = network.constants
|
||||||
do {
|
do {
|
||||||
let path = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
|
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 {
|
} catch {
|
||||||
return URL(fileURLWithPath: "file://\(constants.DEFAULT_CACHES_DB_NAME)")
|
return URL(fileURLWithPath: "file://\(constants.defaultCacheDbName)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,10 @@
|
||||||
// Created by Jack Grigg on 5/8/19.
|
// Created by Jack Grigg on 5/8/19.
|
||||||
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
||||||
//
|
//
|
||||||
|
// swiftlint:disable type_body_length
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class ZcashRustBackend: ZcashRustBackendWelding {
|
class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
|
|
||||||
static func lastError() -> RustWeldingError? {
|
static func lastError() -> RustWeldingError? {
|
||||||
guard let message = getLastError() else { return nil }
|
guard let message = getLastError() else { return nil }
|
||||||
zcashlc_clear_last_error()
|
zcashlc_clear_last_error()
|
||||||
|
@ -127,15 +126,15 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
|
|
||||||
let extpubCStr = [CChar](String(uvk.extpub).utf8CString)
|
let extpubCStr = [CChar](String(uvk.extpub).utf8CString)
|
||||||
let extpubPtr = UnsafeMutablePointer<CChar>.allocate(capacity: extpubCStr.count)
|
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))
|
ffiUvks.append(FFIUnifiedViewingKey(extfvk: extfvkPtr, extpub: extpubPtr))
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = false
|
var result = false
|
||||||
ffiUvks.withContiguousMutableStorageIfAvailable { p in
|
ffiUvks.withContiguousMutableStorageIfAvailable { pointer in
|
||||||
let slice = UnsafeMutablePointer<FFIUVKBoxedSlice>.allocate(capacity: 1)
|
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)
|
result = zcashlc_init_accounts_table_with_keys(dbData.0, dbData.1, slice, networkType.networkId)
|
||||||
slice.deinitialize(count: 1)
|
slice.deinitialize(count: 1)
|
||||||
|
@ -149,10 +148,16 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// swiftlint:disable function_parameter_count
|
||||||
static func initBlocksTable(dbData: URL, height: Int32, hash: String, time: UInt32, saplingTree: String, networkType: NetworkType) throws {
|
static func initBlocksTable(
|
||||||
|
dbData: URL,
|
||||||
|
height: Int32,
|
||||||
|
hash: String,
|
||||||
|
time: UInt32,
|
||||||
|
saplingTree: String,
|
||||||
|
networkType: NetworkType
|
||||||
|
) throws {
|
||||||
let dbData = dbData.osStr()
|
let dbData = dbData.osStr()
|
||||||
|
|
||||||
guard !hash.containsCStringNullBytesBeforeStringEnding() else {
|
guard !hash.containsCStringNullBytesBeforeStringEnding() else {
|
||||||
|
@ -163,7 +168,15 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
throw RustWeldingError.malformedStringInput
|
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() {
|
if let error = lastError() {
|
||||||
throw error
|
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
|
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()
|
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 {
|
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 dbData = dbData.osStr()
|
||||||
let memoBytes = memo ?? ""
|
let memoBytes = memo ?? ""
|
||||||
|
|
||||||
return zcashlc_create_to_address(dbData.0,
|
return zcashlc_create_to_address(
|
||||||
dbData.1,
|
dbData.0,
|
||||||
account,
|
dbData.1,
|
||||||
[CChar](extsk.utf8CString),
|
account,
|
||||||
[CChar](to.utf8CString),
|
[CChar](extsk.utf8CString),
|
||||||
value,
|
[CChar](to.utf8CString),
|
||||||
[CChar](memoBytes.utf8CString),
|
value,
|
||||||
spendParamsPath,
|
[CChar](memoBytes.utf8CString),
|
||||||
UInt(spendParamsPath.lengthOfBytes(using: .utf8)),
|
spendParamsPath,
|
||||||
outputParamsPath,
|
UInt(spendParamsPath.lengthOfBytes(using: .utf8)),
|
||||||
UInt(outputParamsPath.lengthOfBytes(using: .utf8)),
|
outputParamsPath,
|
||||||
networkType.networkId)
|
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 dbData = dbData.osStr()
|
||||||
let memoBytes = memo ?? ""
|
let memoBytes = memo ?? ""
|
||||||
|
|
||||||
return zcashlc_shield_funds(dbData.0,
|
return zcashlc_shield_funds(
|
||||||
dbData.1,
|
dbData.0,
|
||||||
account,
|
dbData.1,
|
||||||
[CChar](tsk.utf8CString),
|
account,
|
||||||
[CChar](extsk.utf8CString),
|
[CChar](tsk.utf8CString),
|
||||||
[CChar](memoBytes.utf8CString),
|
[CChar](extsk.utf8CString),
|
||||||
spendParamsPath,
|
[CChar](memoBytes.utf8CString),
|
||||||
UInt(spendParamsPath.lengthOfBytes(using: .utf8)),
|
spendParamsPath,
|
||||||
outputParamsPath,
|
UInt(spendParamsPath.lengthOfBytes(using: .utf8)),
|
||||||
UInt(outputParamsPath.lengthOfBytes(using: .utf8)),
|
outputParamsPath,
|
||||||
networkType.networkId)
|
UInt(outputParamsPath.lengthOfBytes(using: .utf8)),
|
||||||
|
networkType.networkId
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func deriveExtendedFullViewingKey(_ spendingKey: String, networkType: NetworkType) throws -> String? {
|
static func deriveExtendedFullViewingKey(_ spendingKey: String, networkType: NetworkType) throws -> String? {
|
||||||
|
|
||||||
guard !spendingKey.containsCStringNullBytesBeforeStringEnding() else {
|
guard !spendingKey.containsCStringNullBytesBeforeStringEnding() else {
|
||||||
throw RustWeldingError.malformedStringInput
|
throw RustWeldingError.malformedStringInput
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let extsk = zcashlc_derive_extended_full_viewing_key([CChar](spendingKey.utf8CString),
|
guard let extsk = zcashlc_derive_extended_full_viewing_key(
|
||||||
networkType.networkId) else {
|
[CChar](spendingKey.utf8CString),
|
||||||
|
networkType.networkId
|
||||||
|
) else {
|
||||||
if let error = lastError() {
|
if let error = lastError() {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
@ -377,7 +405,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
}
|
}
|
||||||
|
|
||||||
static func deriveExtendedFullViewingKeys(seed: [UInt8], accounts: Int32, networkType: NetworkType) throws -> [String]? {
|
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 {
|
guard let extsksCStr = zcashlc_derive_extended_full_viewing_keys(seed, UInt(seed.count), accounts, &capacity, networkType.networkId) else {
|
||||||
if let error = lastError() {
|
if let error = lastError() {
|
||||||
throw error
|
throw error
|
||||||
|
@ -385,16 +413,17 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
return nil
|
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 }
|
guard let str = cStr else { return nil }
|
||||||
return String(cString: str)
|
return String(cString: str)
|
||||||
})
|
}
|
||||||
|
|
||||||
zcashlc_vec_string_free(extsksCStr, UInt(accounts), capacity)
|
zcashlc_vec_string_free(extsksCStr, UInt(accounts), capacity)
|
||||||
return extsks
|
return extsks
|
||||||
}
|
}
|
||||||
|
|
||||||
static func deriveExtendedSpendingKeys(seed: [UInt8], accounts: Int32, networkType: NetworkType) throws -> [String]? {
|
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 {
|
guard let extsksCStr = zcashlc_derive_extended_spending_keys(seed, UInt(seed.count), accounts, &capacity, networkType.networkId) else {
|
||||||
if let error = lastError() {
|
if let error = lastError() {
|
||||||
throw error
|
throw error
|
||||||
|
@ -402,31 +431,35 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
return nil
|
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 }
|
guard let str = cStr else { return nil }
|
||||||
return String(cString: str)
|
return String(cString: str)
|
||||||
})
|
}
|
||||||
zcashlc_vec_string_free(extsksCStr, UInt(accounts), capacity)
|
zcashlc_vec_string_free(extsksCStr, UInt(accounts), capacity)
|
||||||
return extsks
|
return extsks
|
||||||
}
|
}
|
||||||
|
|
||||||
static func deriveUnifiedViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int, networkType: NetworkType) throws -> [UnifiedViewingKey] {
|
static func deriveUnifiedViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int, networkType: NetworkType) throws -> [UnifiedViewingKey] {
|
||||||
|
guard let uvksStruct = zcashlc_derive_unified_viewing_keys_from_seed(
|
||||||
guard let uvks_struct = zcashlc_derive_unified_viewing_keys_from_seed(seed, UInt(seed.count), Int32(numberOfAccounts), networkType.networkId) else {
|
seed,
|
||||||
|
UInt(seed.count),
|
||||||
|
Int32(numberOfAccounts),
|
||||||
|
networkType.networkId
|
||||||
|
) else {
|
||||||
if let error = lastError() {
|
if let error = lastError() {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
throw RustWeldingError.unableToDeriveKeys
|
throw RustWeldingError.unableToDeriveKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
let uvks_size = uvks_struct.pointee.len
|
let uvksSize = uvksStruct.pointee.len
|
||||||
guard let uvks_array_pointer = uvks_struct.pointee.ptr, uvks_size > 0 else {
|
guard let uvksArrayPointer = uvksStruct.pointee.ptr, uvksSize > 0 else {
|
||||||
throw RustWeldingError.unableToDeriveKeys
|
throw RustWeldingError.unableToDeriveKeys
|
||||||
}
|
}
|
||||||
var uvks = [UnifiedViewingKey]()
|
var uvks = [UnifiedViewingKey]()
|
||||||
|
|
||||||
for i: Int in 0 ..< Int(uvks_size) {
|
for i: Int in 0 ..< Int(uvksSize) {
|
||||||
let itemPointer = uvks_array_pointer.advanced(by: i)
|
let itemPointer = uvksArrayPointer.advanced(by: i)
|
||||||
|
|
||||||
guard let extfvk = String(validatingUTF8: itemPointer.pointee.extfvk) else {
|
guard let extfvk = String(validatingUTF8: itemPointer.pointee.extfvk) else {
|
||||||
throw RustWeldingError.unableToDeriveKeys
|
throw RustWeldingError.unableToDeriveKeys
|
||||||
|
@ -439,12 +472,16 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
uvks.append(UVK(extfvk: extfvk, extpub: extpub))
|
uvks.append(UVK(extfvk: extfvk, extpub: extpub))
|
||||||
}
|
}
|
||||||
|
|
||||||
zcashlc_free_uvk_array(uvks_struct)
|
zcashlc_free_uvk_array(uvksStruct)
|
||||||
|
|
||||||
return uvks
|
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 {
|
guard let zaddrCStr = zcashlc_derive_shielded_address_from_seed(seed, UInt(seed.count), accountIndex, networkType.networkId) else {
|
||||||
if let error = lastError() {
|
if let error = lastError() {
|
||||||
throw error
|
throw error
|
||||||
|
@ -458,12 +495,17 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
return zAddr
|
return zAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
static func deriveShieldedAddressFromViewingKey(_ extfvk: String, networkType: NetworkType) throws -> String? {
|
static func deriveShieldedAddressFromViewingKey(
|
||||||
|
_ extfvk: String,
|
||||||
|
networkType: NetworkType
|
||||||
|
) throws -> String? {
|
||||||
guard !extfvk.containsCStringNullBytesBeforeStringEnding() else {
|
guard !extfvk.containsCStringNullBytesBeforeStringEnding() else {
|
||||||
throw RustWeldingError.malformedStringInput
|
throw RustWeldingError.malformedStringInput
|
||||||
}
|
}
|
||||||
|
guard let zaddrCStr = zcashlc_derive_shielded_address_from_viewing_key(
|
||||||
guard let zaddrCStr = zcashlc_derive_shielded_address_from_viewing_key([CChar](extfvk.utf8CString), networkType.networkId) else {
|
[CChar](extfvk.utf8CString),
|
||||||
|
networkType.networkId
|
||||||
|
) else {
|
||||||
if let error = lastError() {
|
if let error = lastError() {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
@ -476,7 +518,12 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
return zAddr
|
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 {
|
guard let tAddrCStr = zcashlc_derive_transparent_address_from_seed(seed, UInt(seed.count), Int32(account), Int32(index), networkType.networkId) else {
|
||||||
if let error = lastError() {
|
if let error = lastError() {
|
||||||
|
@ -490,7 +537,12 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
return tAddr
|
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 {
|
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() {
|
if let error = lastError() {
|
||||||
throw error
|
throw error
|
||||||
|
@ -502,12 +554,18 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
return sk
|
return sk
|
||||||
}
|
}
|
||||||
|
|
||||||
static func derivedTransparentAddressFromPublicKey(_ pubkey: String, networkType: NetworkType) throws -> String {
|
static func derivedTransparentAddressFromPublicKey(
|
||||||
|
_ pubkey: String,
|
||||||
|
networkType: NetworkType
|
||||||
|
) throws -> String {
|
||||||
guard !pubkey.containsCStringNullBytesBeforeStringEnding() else {
|
guard !pubkey.containsCStringNullBytesBeforeStringEnding() else {
|
||||||
throw RustWeldingError.malformedStringInput
|
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() {
|
if let error = lastError() {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
@ -541,7 +599,6 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
|
|
||||||
return branchId
|
return branchId
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct UVK: UnifiedViewingKey {
|
private struct UVK: UnifiedViewingKey {
|
||||||
|
@ -551,26 +608,21 @@ private struct UVK: UnifiedViewingKey {
|
||||||
|
|
||||||
private extension ZcashRustBackend {
|
private extension ZcashRustBackend {
|
||||||
static func throwDataDbError(_ error: RustWeldingError) -> Error {
|
static func throwDataDbError(_ error: RustWeldingError) -> Error {
|
||||||
|
|
||||||
if case RustWeldingError.genericError(let message) = error, message.contains("is not empty") {
|
if case RustWeldingError.genericError(let message) = error, message.contains("is not empty") {
|
||||||
return RustWeldingError.dataDbNotEmpty
|
return RustWeldingError.dataDbNotEmpty
|
||||||
}
|
}
|
||||||
return RustWeldingError.dataDbInitFailed(message: error.localizedDescription)
|
return RustWeldingError.dataDbInitFailed(message: error.localizedDescription)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension URL {
|
private extension URL {
|
||||||
|
|
||||||
func osStr() -> (String, UInt) {
|
func osStr() -> (String, UInt) {
|
||||||
let path = self.absoluteString
|
let path = self.absoluteString
|
||||||
return (path, UInt(path.lengthOfBytes(using: .utf8)))
|
return (path, UInt(path.lengthOfBytes(using: .utf8)))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension String {
|
extension String {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Checks whether this string contains null bytes before it's real ending
|
Checks whether this string contains null bytes before it's real ending
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -81,7 +81,15 @@ public protocol ZcashRustBackendWelding {
|
||||||
- time: in milliseconds from reference
|
- time: in milliseconds from reference
|
||||||
- saplingTree: hash of the sapling tree
|
- 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
|
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.
|
- minedHeight: height on which this transaction was mined. this is used to fetch the consensus branch ID.
|
||||||
returns false if fails to decrypt.
|
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
|
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
|
- 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
|
- 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.
|
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
|
- 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
|
- 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
|
Derives a full viewing key from a seed
|
||||||
|
|
|
@ -164,18 +164,31 @@ public class LightWalletGRPCService {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension LightWalletGRPCService: LightWalletService {
|
extension LightWalletGRPCService: LightWalletService {
|
||||||
|
@discardableResult public func blockStream(
|
||||||
@discardableResult public func blockStream(startHeight: BlockHeight, endHeight: BlockHeight, result: @escaping (Result<GRPCResult, LightWalletServiceError>) -> Void, handler: @escaping (ZcashCompactBlock) -> Void, progress: @escaping (BlockProgressReporting) -> Void) -> CancellableCall {
|
startHeight: BlockHeight,
|
||||||
|
endHeight: BlockHeight,
|
||||||
let future = compactTxStreamer.getBlockRange(BlockRange(startHeight: startHeight, endHeight: endHeight), callOptions: Self.callOptions(timeLimit: self.streamingCallTimeout), handler: { compactBlock in
|
result: @escaping (Result<GRPCResult, LightWalletServiceError>) -> Void,
|
||||||
|
handler: @escaping (ZcashCompactBlock) -> Void,
|
||||||
handler(ZcashCompactBlock(compactBlock: compactBlock))
|
progress: @escaping (BlockProgressReporting) -> Void
|
||||||
progress(BlockProgress(startHeight: startHeight, targetHeight: endHeight, progressHeight: BlockHeight(compactBlock.height)))
|
) -> 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
|
future.status.whenComplete { completionResult in
|
||||||
switch r {
|
switch completionResult {
|
||||||
case .success(let status):
|
case .success(let status):
|
||||||
switch status.code {
|
switch status.code {
|
||||||
case .ok:
|
case .ok:
|
||||||
|
@ -195,8 +208,8 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getInfo(result: @escaping (Result<LightWalletdInfo, LightWalletServiceError>) -> Void) {
|
public func getInfo(result: @escaping (Result<LightWalletdInfo, LightWalletServiceError>) -> Void) {
|
||||||
compactTxStreamer.getLightdInfo(Empty()).response.whenComplete { r in
|
compactTxStreamer.getLightdInfo(Empty()).response.whenComplete { completionResult in
|
||||||
switch r {
|
switch completionResult {
|
||||||
case .success(let info):
|
case .success(let info):
|
||||||
result(.success(info))
|
result(.success(info))
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
|
@ -223,19 +236,17 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
|
public func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
|
||||||
|
|
||||||
var txFilter = TxFilter()
|
var txFilter = TxFilter()
|
||||||
txFilter.hash = txId
|
txFilter.hash = txId
|
||||||
|
|
||||||
compactTxStreamer.getTransaction(txFilter).response.whenComplete({ response in
|
compactTxStreamer.getTransaction(txFilter).response.whenComplete { response in
|
||||||
|
|
||||||
switch response {
|
switch response {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
result(.failure(error.mapToServiceError()))
|
result(.failure(error.mapToServiceError()))
|
||||||
case .success(let rawTx):
|
case .success(let rawTx):
|
||||||
result(.success(TransactionBuilder.createTransactionEntity(txId: txId, rawTransaction: rawTx)))
|
result(.success(TransactionBuilder.createTransactionEntity(txId: txId, rawTransaction: rawTx)))
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func submit(spendTransaction: Data, result: @escaping (Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
|
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 tx = try RawTransaction(serializedData: spendTransaction)
|
||||||
let response = self.compactTxStreamer.sendTransaction(tx).response
|
let response = self.compactTxStreamer.sendTransaction(tx).response
|
||||||
|
|
||||||
response.whenComplete { (responseResult) in
|
response.whenComplete { responseResult in
|
||||||
switch responseResult {
|
switch responseResult {
|
||||||
case .failure(let e):
|
case .failure(let error):
|
||||||
result(.failure(LightWalletServiceError.sentFailed(error: e)))
|
result(.failure(LightWalletServiceError.sentFailed(error: error)))
|
||||||
case .success(let s):
|
case .success(let success):
|
||||||
result(.success(s))
|
result(.success(success))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -257,8 +268,7 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
|
public func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
|
||||||
|
let rawTx = RawTransaction.with { raw in
|
||||||
let rawTx = RawTransaction.with { (raw) in
|
|
||||||
raw.data = spendTransaction
|
raw.data = spendTransaction
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
|
@ -273,14 +283,15 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
|
|
||||||
let response = compactTxStreamer.getBlockRange(range.blockRange(), handler: {
|
let response = compactTxStreamer.getBlockRange(range.blockRange(), handler: {
|
||||||
blocks.append($0)
|
blocks.append($0)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
let status = try response.status.wait()
|
let status = try response.status.wait()
|
||||||
switch status.code {
|
switch status.code {
|
||||||
case .ok:
|
case .ok:
|
||||||
return blocks.asZcashCompactBlocks()
|
return blocks.asZcashCompactBlocks()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw LightWalletServiceError.mapCode(status)
|
throw LightWalletServiceError.mapCode(status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,13 +310,10 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
response.whenFailureBlocking(onto: queue) { error in
|
response.whenFailureBlocking(onto: queue) { error in
|
||||||
result(.failure(error.mapToServiceError()))
|
result(.failure(error.mapToServiceError()))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void) {
|
public func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void) {
|
||||||
|
|
||||||
queue.async { [weak self] in
|
queue.async { [weak self] in
|
||||||
|
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
var blocks = [CompactBlock]()
|
var blocks = [CompactBlock]()
|
||||||
|
@ -321,7 +329,6 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
default:
|
default:
|
||||||
result(.failure(.mapCode(status)))
|
result(.failure(.mapCode(status)))
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
result(.failure(error.mapToServiceError()))
|
result(.failure(error.mapToServiceError()))
|
||||||
}
|
}
|
||||||
|
@ -329,7 +336,6 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func latestBlockHeight() throws -> BlockHeight {
|
public func latestBlockHeight() throws -> BlockHeight {
|
||||||
|
|
||||||
guard let height = try? latestBlock().compactBlockHeight() else {
|
guard let height = try? latestBlock().compactBlockHeight() else {
|
||||||
throw LightWalletServiceError.invalidBlock
|
throw LightWalletServiceError.invalidBlock
|
||||||
}
|
}
|
||||||
|
@ -337,20 +343,21 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
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.addresses = [tAddress]
|
||||||
utxoArgs.startHeight = UInt64(height)
|
utxoArgs.startHeight = UInt64(height)
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
return try self.compactTxStreamer.getAddressUtxos(arg).response.wait().addressUtxos.map { reply in
|
return try self.compactTxStreamer.getAddressUtxos(arg).response.wait().addressUtxos.map { reply in
|
||||||
UTXO(id: nil,
|
UTXO(
|
||||||
address: tAddress,
|
id: nil,
|
||||||
prevoutTxId: reply.txid,
|
address: tAddress,
|
||||||
prevoutIndex: Int(reply.index),
|
prevoutTxId: reply.txid,
|
||||||
script: reply.script,
|
prevoutIndex: Int(reply.index),
|
||||||
valueZat: Int(reply.valueZat),
|
script: reply.script,
|
||||||
height: Int(reply.height),
|
valueZat: Int(reply.valueZat),
|
||||||
spentInTx: nil
|
height: Int(reply.height),
|
||||||
|
spentInTx: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -361,21 +368,22 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
public func fetchUTXOs(for tAddress: String, height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) {
|
public func fetchUTXOs(for tAddress: String, height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) {
|
||||||
queue.async { [weak self] in
|
queue.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
let arg = GetAddressUtxosArg.with { (utxoArgs) in
|
let arg = GetAddressUtxosArg.with { utxoArgs in
|
||||||
utxoArgs.addresses = [tAddress]
|
utxoArgs.addresses = [tAddress]
|
||||||
utxoArgs.startHeight = UInt64(height)
|
utxoArgs.startHeight = UInt64(height)
|
||||||
}
|
}
|
||||||
var utxos = [UnspentTransactionOutputEntity]()
|
var utxos = [UnspentTransactionOutputEntity]()
|
||||||
let response = self.compactTxStreamer.getAddressUtxosStream(arg) { (reply) in
|
let response = self.compactTxStreamer.getAddressUtxosStream(arg) { reply in
|
||||||
utxos.append(
|
utxos.append(
|
||||||
UTXO(id: nil,
|
UTXO(
|
||||||
address: tAddress,
|
id: nil,
|
||||||
prevoutTxId: reply.txid,
|
address: tAddress,
|
||||||
prevoutIndex: Int(reply.index),
|
prevoutTxId: reply.txid,
|
||||||
script: reply.script,
|
prevoutIndex: Int(reply.index),
|
||||||
valueZat: Int(reply.valueZat),
|
script: reply.script,
|
||||||
height: Int(reply.height),
|
valueZat: Int(reply.valueZat),
|
||||||
spentInTx: nil
|
height: Int(reply.height),
|
||||||
|
spentInTx: nil
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -395,37 +403,37 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func fetchUTXOs(for tAddresses: [String], height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
public func fetchUTXOs(for tAddresses: [String], height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
||||||
|
guard !tAddresses.isEmpty else {
|
||||||
guard tAddresses.count > 0 else {
|
|
||||||
return [] // FIXME: throw a real error
|
return [] // FIXME: throw a real error
|
||||||
}
|
}
|
||||||
|
|
||||||
var utxos = [UnspentTransactionOutputEntity]()
|
var utxos = [UnspentTransactionOutputEntity]()
|
||||||
|
|
||||||
let arg = GetAddressUtxosArg.with { (utxoArgs) in
|
let arg = GetAddressUtxosArg.with { utxoArgs in
|
||||||
utxoArgs.addresses = tAddresses
|
utxoArgs.addresses = tAddresses
|
||||||
utxoArgs.startHeight = UInt64(height)
|
utxoArgs.startHeight = UInt64(height)
|
||||||
}
|
}
|
||||||
utxos.append(contentsOf:
|
utxos.append(
|
||||||
try self.compactTxStreamer.getAddressUtxos(arg).response.wait().addressUtxos.map({ reply in
|
contentsOf:
|
||||||
UTXO(id: nil,
|
try self.compactTxStreamer.getAddressUtxos(arg).response.wait().addressUtxos.map { reply in
|
||||||
address: reply.address,
|
UTXO(
|
||||||
prevoutTxId: reply.txid,
|
id: nil,
|
||||||
prevoutIndex: Int(reply.index),
|
address: reply.address,
|
||||||
script: reply.script,
|
prevoutTxId: reply.txid,
|
||||||
valueZat: Int(reply.valueZat),
|
prevoutIndex: Int(reply.index),
|
||||||
height: Int(reply.height),
|
script: reply.script,
|
||||||
spentInTx: nil)
|
valueZat: Int(reply.valueZat),
|
||||||
})
|
height: Int(reply.height),
|
||||||
|
spentInTx: nil
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
return utxos
|
return utxos
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func fetchUTXOs(for tAddresses: [String], height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) {
|
public func fetchUTXOs(for tAddresses: [String], height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) {
|
||||||
|
guard !tAddresses.isEmpty else {
|
||||||
guard tAddresses.count > 0 else {
|
|
||||||
return result(.success([])) // FIXME: throw a real error
|
return result(.success([])) // FIXME: throw a real error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,16 +447,20 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
do {
|
do {
|
||||||
let response = try self.compactTxStreamer.getAddressUtxosStream(args) { reply in
|
let response = try self.compactTxStreamer.getAddressUtxosStream(args) { reply in
|
||||||
utxos.append(
|
utxos.append(
|
||||||
UTXO(id: nil,
|
UTXO(
|
||||||
address: reply.address,
|
id: nil,
|
||||||
prevoutTxId: reply.txid,
|
address: reply.address,
|
||||||
prevoutIndex: Int(reply.index),
|
prevoutTxId: reply.txid,
|
||||||
script: reply.script,
|
prevoutIndex: Int(reply.index),
|
||||||
valueZat: Int(reply.valueZat),
|
script: reply.script,
|
||||||
height: Int(reply.height),
|
valueZat: Int(reply.valueZat),
|
||||||
spentInTx: nil)
|
height: Int(reply.height),
|
||||||
|
spentInTx: nil
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}.status.wait()
|
}
|
||||||
|
.status
|
||||||
|
.wait()
|
||||||
switch response.code {
|
switch response.code {
|
||||||
case .ok:
|
case .ok:
|
||||||
result(.success(utxos))
|
result(.success(utxos))
|
||||||
|
@ -476,7 +488,6 @@ extension Error {
|
||||||
extension LightWalletServiceError {
|
extension LightWalletServiceError {
|
||||||
static func mapCode(_ status: GRPCStatus) -> LightWalletServiceError {
|
static func mapCode(_ status: GRPCStatus) -> LightWalletServiceError {
|
||||||
switch status.code {
|
switch status.code {
|
||||||
|
|
||||||
case .ok:
|
case .ok:
|
||||||
return LightWalletServiceError.unknown
|
return LightWalletServiceError.unknown
|
||||||
case .cancelled:
|
case .cancelled:
|
||||||
|
@ -499,8 +510,9 @@ class ConnectionStatusManager: ConnectivityStateDelegate {
|
||||||
name: .blockProcessorConnectivityStateChanged,
|
name: .blockProcessorConnectivityStateChanged,
|
||||||
object: self,
|
object: self,
|
||||||
userInfo: [
|
userInfo: [
|
||||||
CompactBlockProcessorNotificationKey.currentConnectivityStatus : newState,
|
CompactBlockProcessorNotificationKey.currentConnectivityStatus: newState,
|
||||||
CompactBlockProcessorNotificationKey.previousConnectivityStatus : oldState
|
CompactBlockProcessorNotificationKey.previousConnectivityStatus: oldState
|
||||||
])
|
]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@ public protocol BlockProgressReporting {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension LightWalletServiceError: Equatable {
|
extension LightWalletServiceError: Equatable {
|
||||||
|
// swiftlint:disable cyclomatic_complexity
|
||||||
|
// swiftlint:disable identifier_name
|
||||||
public static func == (lhs: Self, rhs: Self) -> Bool {
|
public static func == (lhs: Self, rhs: Self) -> Bool {
|
||||||
switch lhs {
|
switch lhs {
|
||||||
case .generalError(let m):
|
case .generalError(let m):
|
||||||
|
@ -74,21 +76,21 @@ extension LightWalletServiceError: Equatable {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case .criticalError:
|
case .criticalError:
|
||||||
switch rhs {
|
switch rhs {
|
||||||
case .criticalError:
|
case .criticalError:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case .userCancelled:
|
case .userCancelled:
|
||||||
switch rhs {
|
switch rhs {
|
||||||
case .userCancelled:
|
case .userCancelled:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case .unknown:
|
case .unknown:
|
||||||
switch rhs {
|
switch rhs {
|
||||||
case .unknown:
|
case .unknown:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
|
@ -121,7 +123,7 @@ public protocol LightWalletService {
|
||||||
|
|
||||||
- Parameter result: a result containing the height or an Error
|
- 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.
|
Return the latest block height known to the service.
|
||||||
|
@ -150,13 +152,19 @@ public protocol LightWalletService {
|
||||||
*/
|
*/
|
||||||
func blockRange(_ range: CompactBlockRange) throws -> [ZcashCompactBlock]
|
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
|
Submits a raw transaction over lightwalletd. Non-Blocking
|
||||||
- Parameter spendTransaction: data representing the transaction to be sent
|
- Parameter spendTransaction: data representing the transaction to be sent
|
||||||
- Parameter result: escaping closure that takes a result containing either LightWalletServiceResponse or LightWalletServiceError
|
- 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
|
Submits a raw transaction over lightwalletd. Blocking
|
||||||
|
@ -183,7 +191,7 @@ public protocol LightWalletService {
|
||||||
- Throws: LightWalletServiceError
|
- Throws: LightWalletServiceError
|
||||||
- Returns: LightWalletServiceResponse
|
- 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]
|
func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity]
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||||
|
|
||||||
|
// swiftlint:disable all
|
||||||
import Foundation
|
import Foundation
|
||||||
import SwiftProtobuf
|
import SwiftProtobuf
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||||
|
|
||||||
|
// swiftlint:disable all
|
||||||
import Foundation
|
import Foundation
|
||||||
import SwiftProtobuf
|
import SwiftProtobuf
|
||||||
|
|
||||||
|
|
|
@ -51,22 +51,46 @@ class PersistentTransactionManager: OutboundTransactionManager {
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
let derivationTool = DerivationTool(networkType: self.network)
|
let derivationTool = DerivationTool(networkType: self.network)
|
||||||
guard let vk = try? derivationTool.deriveViewingKey(spendingKey: spendingKey),
|
guard let viewingKey = try? derivationTool.deriveViewingKey(spendingKey: spendingKey),
|
||||||
let zAddr = try? derivationTool.deriveShieldedAddress(viewingKey: vk) else {
|
let zAddr = try? derivationTool.deriveShieldedAddress(viewingKey: viewingKey) else {
|
||||||
result(.failure(TransactionManagerError.shieldingEncodingFailed(tx: pendingTransaction, reason: "There was an error Deriving your keys")))
|
result(
|
||||||
return
|
.failure(
|
||||||
|
TransactionManagerError.shieldingEncodingFailed(
|
||||||
|
tx: pendingTransaction,
|
||||||
|
reason: "There was an error Deriving your keys")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard pendingTransaction.toAddress == zAddr else {
|
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
|
return
|
||||||
}
|
}
|
||||||
do {
|
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)
|
let transaction = try self.encoder.expandEncodedTransaction(encodedTransaction)
|
||||||
|
|
||||||
var pending = pendingTransaction
|
var pending = pendingTransaction
|
||||||
pending.encodeAttempts = pending.encodeAttempts + 1
|
pending.encodeAttempts += 1
|
||||||
pending.raw = encodedTransaction.raw
|
pending.raw = encodedTransaction.raw
|
||||||
pending.rawTransactionId = encodedTransaction.transactionId
|
pending.rawTransactionId = encodedTransaction.transactionId
|
||||||
pending.expiryHeight = transaction.expiryHeight ?? BlockHeight.empty()
|
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
|
queue.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
do {
|
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)
|
let transaction = try self.encoder.expandEncodedTransaction(encodedTransaction)
|
||||||
|
|
||||||
var pending = pendingTransaction
|
var pending = pendingTransaction
|
||||||
pending.encodeAttempts = pending.encodeAttempts + 1
|
pending.encodeAttempts += 1
|
||||||
pending.raw = encodedTransaction.raw
|
pending.raw = encodedTransaction.raw
|
||||||
pending.rawTransactionId = encodedTransaction.transactionId
|
pending.rawTransactionId = encodedTransaction.transactionId
|
||||||
pending.expiryHeight = transaction.expiryHeight ?? BlockHeight.empty()
|
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 {
|
guard let txId = pendingTransaction.id else {
|
||||||
result(.failure(TransactionManagerError.notPending(tx: pendingTransaction)))// this transaction is not stored
|
result(.failure(TransactionManagerError.notPending(tx: pendingTransaction)))// this transaction is not stored
|
||||||
return
|
return
|
||||||
|
@ -149,13 +180,13 @@ class PersistentTransactionManager: OutboundTransactionManager {
|
||||||
}
|
}
|
||||||
let response = try self.service.submit(spendTransaction: raw)
|
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 {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result(.success(tx))
|
result(.success(transaction))
|
||||||
} catch {
|
} catch {
|
||||||
try? self.updateOnFailure(tx: pendingTransaction, error: error)
|
try? self.updateOnFailure(tx: pendingTransaction, error: error)
|
||||||
result(.failure(error))
|
result(.failure(error))
|
||||||
|
@ -191,8 +222,8 @@ class PersistentTransactionManager: OutboundTransactionManager {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try affectedTxs.map { (tx) -> PendingTransactionEntity in
|
try affectedTxs.map { (transaction) -> PendingTransactionEntity in
|
||||||
var updatedTx = tx
|
var updatedTx = transaction
|
||||||
updatedTx.minedHeight = -1
|
updatedTx.minedHeight = -1
|
||||||
return updatedTx
|
return updatedTx
|
||||||
} .forEach({ try self.repository.update($0) })
|
} .forEach({ try self.repository.update($0) })
|
||||||
|
@ -227,13 +258,13 @@ class PersistentTransactionManager: OutboundTransactionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func update(transaction: PendingTransactionEntity, on sendResponse: LightWalletServiceResponse) throws -> PendingTransactionEntity {
|
private func update(transaction: PendingTransactionEntity, on sendResponse: LightWalletServiceResponse) throws -> PendingTransactionEntity {
|
||||||
var tx = transaction
|
var pendingTx = transaction
|
||||||
tx.submitAttempts = tx.submitAttempts + 1
|
pendingTx.submitAttempts += 1
|
||||||
let error = sendResponse.errorCode < 0
|
let error = sendResponse.errorCode < 0
|
||||||
tx.errorCode = error ? Int(sendResponse.errorCode) : nil
|
pendingTx.errorCode = error ? Int(sendResponse.errorCode) : nil
|
||||||
tx.errorMessage = error ? sendResponse.errorMessage : nil
|
pendingTx.errorMessage = error ? sendResponse.errorMessage : nil
|
||||||
try repository.update(tx)
|
try repository.update(pendingTx)
|
||||||
return tx
|
return pendingTx
|
||||||
}
|
}
|
||||||
|
|
||||||
func delete(pendingTransaction: PendingTransactionEntity) throws {
|
func delete(pendingTransaction: PendingTransactionEntity) throws {
|
||||||
|
@ -243,18 +274,20 @@ class PersistentTransactionManager: OutboundTransactionManager {
|
||||||
throw TransactionManagerError.notPending(tx: pendingTransaction)
|
throw TransactionManagerError.notPending(tx: pendingTransaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class OutboundTransactionManagerBuilder {
|
enum OutboundTransactionManagerBuilder {
|
||||||
|
|
||||||
static func build(initializer: Initializer) throws -> OutboundTransactionManager {
|
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 {
|
static func build(initializer: Initializer) throws -> PendingTransactionRepository {
|
||||||
let dao = PendingTransactionSQLDAO(dbProvider: SimpleConnectionProvider(path: initializer.pendingDbURL.path, readonly: false))
|
let dao = PendingTransactionSQLDAO(dbProvider: SimpleConnectionProvider(path: initializer.pendingDbURL.path, readonly: false))
|
||||||
try dao.createrTableIfNeeded()
|
try dao.createrTableIfNeeded()
|
||||||
|
@ -262,7 +295,7 @@ class PendingTransactionRepositoryBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TransactionEncoderbuilder {
|
enum TransactionEncoderbuilder {
|
||||||
static func build(initializer: Initializer) -> TransactionEncoder {
|
static func build(initializer: Initializer) -> TransactionEncoder {
|
||||||
WalletTransactionEncoder(initializer: initializer)
|
WalletTransactionEncoder(initializer: initializer)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,11 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
typealias TransactionEncoderResultBlock = (_ result: Result<EncodedTransaction,Error>) -> Void
|
typealias TransactionEncoderResultBlock = (_ result: Result<EncodedTransaction, Error>) -> Void
|
||||||
|
|
||||||
public enum TransactionEncoderError: Error {
|
public enum TransactionEncoderError: Error {
|
||||||
case notFound(transactionId: Int)
|
case notFound(transactionId: Int)
|
||||||
case NotEncoded(transactionId: Int)
|
case notEncoded(transactionId: Int)
|
||||||
case missingParams
|
case missingParams
|
||||||
case spendingKeyWrongNetwork
|
case spendingKeyWrongNetwork
|
||||||
case couldNotExpand(txId: Data)
|
case couldNotExpand(txId: Data)
|
||||||
|
@ -34,7 +34,13 @@ protocol TransactionEncoder {
|
||||||
|
|
||||||
- Throws: a TransactionEncoderError
|
- 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
|
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 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
|
- 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
|
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
|
- 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
|
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
|
- 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
|
Fetch the Transaction Entity from the encoded representation
|
||||||
|
|
|
@ -161,9 +161,9 @@ class WalletTransactionEncoder: TransactionEncoder {
|
||||||
- Throws: a TransactionEncoderError
|
- Throws: a TransactionEncoderError
|
||||||
*/
|
*/
|
||||||
func expandEncodedTransaction(_ encodedTransaction: EncodedTransaction) throws -> TransactionEntity {
|
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)
|
throw TransactionEncoderError.couldNotExpand(txId: encodedTransaction.transactionId)
|
||||||
}
|
}
|
||||||
return t
|
return transaction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,9 +98,9 @@ public extension Notification.Name {
|
||||||
/**
|
/**
|
||||||
Synchronizer implementation for UIKit and iOS 12+
|
Synchronizer implementation for UIKit and iOS 12+
|
||||||
*/
|
*/
|
||||||
|
// swiftlint:disable type_body_length
|
||||||
public class SDKSynchronizer: Synchronizer {
|
public class SDKSynchronizer: Synchronizer {
|
||||||
|
public enum NotificationKeys {
|
||||||
public struct NotificationKeys {
|
|
||||||
public static let progress = "SDKSynchronizer.progress"
|
public static let progress = "SDKSynchronizer.progress"
|
||||||
public static let blockHeight = "SDKSynchronizer.blockHeight"
|
public static let blockHeight = "SDKSynchronizer.blockHeight"
|
||||||
public static let blockDate = "SDKSynchronizer.blockDate"
|
public static let blockDate = "SDKSynchronizer.blockDate"
|
||||||
|
@ -135,22 +135,23 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
- Parameter initializer: a wallet Initializer object
|
- Parameter initializer: a wallet Initializer object
|
||||||
*/
|
*/
|
||||||
public convenience init(initializer: Initializer) throws {
|
public convenience init(initializer: Initializer) throws {
|
||||||
|
try self.init(
|
||||||
try self.init(status: .unprepared,
|
status: .unprepared,
|
||||||
initializer: initializer,
|
initializer: initializer,
|
||||||
transactionManager: try OutboundTransactionManagerBuilder.build(initializer: initializer),
|
transactionManager: try OutboundTransactionManagerBuilder.build(initializer: initializer),
|
||||||
transactionRepository: initializer.transactionRepository,
|
transactionRepository: initializer.transactionRepository,
|
||||||
utxoRepository: try UTXORepositoryBuilder.build(initializer: initializer),
|
utxoRepository: try UTXORepositoryBuilder.build(initializer: initializer),
|
||||||
blockProcessor: CompactBlockProcessor(initializer: initializer))
|
blockProcessor: CompactBlockProcessor(initializer: initializer))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init(status: SyncStatus,
|
init(
|
||||||
initializer: Initializer,
|
status: SyncStatus,
|
||||||
transactionManager: OutboundTransactionManager,
|
initializer: Initializer,
|
||||||
transactionRepository: TransactionRepository,
|
transactionManager: OutboundTransactionManager,
|
||||||
utxoRepository: UnspentTransactionOutputRepository,
|
transactionRepository: TransactionRepository,
|
||||||
blockProcessor: CompactBlockProcessor) throws {
|
utxoRepository: UnspentTransactionOutputRepository,
|
||||||
|
blockProcessor: CompactBlockProcessor
|
||||||
|
) throws {
|
||||||
self.connectionState = .idle
|
self.connectionState = .idle
|
||||||
self.status = status
|
self.status = status
|
||||||
self.initializer = initializer
|
self.initializer = initializer
|
||||||
|
@ -183,7 +184,6 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
- Throws: CompactBlockProcessorError when failures occur
|
- Throws: CompactBlockProcessorError when failures occur
|
||||||
*/
|
*/
|
||||||
public func start(retry: Bool = false) throws {
|
public func start(retry: Bool = false) throws {
|
||||||
|
|
||||||
switch status {
|
switch status {
|
||||||
case .unprepared:
|
case .unprepared:
|
||||||
throw SynchronizerError.notPrepared
|
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
|
// 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")
|
LoggerProxy.warn("warning: synchronizer started when already started")
|
||||||
return
|
return
|
||||||
case .stopped, .synced,.disconnected, .error:
|
case .stopped, .synced, .disconnected, .error:
|
||||||
do {
|
do {
|
||||||
try blockProcessor.start(retry: retry)
|
try blockProcessor.start(retry: retry)
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -208,7 +208,6 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
Stops the synchronizer
|
Stops the synchronizer
|
||||||
*/
|
*/
|
||||||
public func stop() {
|
public func stop() {
|
||||||
|
|
||||||
guard status != .stopped, status != .disconnected else {
|
guard status != .stopped, status != .disconnected else {
|
||||||
LoggerProxy.info("attempted to stop when status was: \(status)")
|
LoggerProxy.info("attempted to stop when status was: \(status)")
|
||||||
return
|
return
|
||||||
|
@ -221,74 +220,103 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
private func subscribeToProcessorNotifications(_ processor: CompactBlockProcessor) {
|
private func subscribeToProcessorNotifications(_ processor: CompactBlockProcessor) {
|
||||||
let center = NotificationCenter.default
|
let center = NotificationCenter.default
|
||||||
|
|
||||||
center.addObserver(self,
|
center.addObserver(
|
||||||
selector: #selector(processorUpdated(_:)),
|
self,
|
||||||
name: Notification.Name.blockProcessorUpdated,
|
selector: #selector(processorUpdated(_:)),
|
||||||
object: processor)
|
name: Notification.Name.blockProcessorUpdated,
|
||||||
|
object: processor
|
||||||
|
)
|
||||||
|
|
||||||
center.addObserver(self,
|
center.addObserver(
|
||||||
selector: #selector(processorStartedDownloading(_:)),
|
self,
|
||||||
name: Notification.Name.blockProcessorStartedDownloading,
|
selector: #selector(processorStartedDownloading(_:)),
|
||||||
object: processor)
|
name: Notification.Name.blockProcessorStartedDownloading,
|
||||||
|
object: processor
|
||||||
|
)
|
||||||
|
|
||||||
center.addObserver(self,
|
center.addObserver(
|
||||||
selector: #selector(processorStartedValidating(_:)),
|
self,
|
||||||
name: Notification.Name.blockProcessorStartedValidating,
|
selector: #selector(processorStartedValidating(_:)),
|
||||||
object: processor)
|
name: Notification.Name.blockProcessorStartedValidating,
|
||||||
|
object: processor
|
||||||
|
)
|
||||||
|
|
||||||
center.addObserver(self,
|
center.addObserver(
|
||||||
selector: #selector(processorStartedScanning(_:)),
|
self,
|
||||||
name: Notification.Name.blockProcessorStartedScanning,
|
selector: #selector(processorStartedScanning(_:)),
|
||||||
object: processor)
|
name: Notification.Name.blockProcessorStartedScanning,
|
||||||
|
object: processor
|
||||||
|
)
|
||||||
|
|
||||||
center.addObserver(self,
|
center.addObserver(
|
||||||
selector: #selector(processorStartedEnhancing(_:)),
|
self,
|
||||||
name: Notification.Name.blockProcessorStartedEnhancing,
|
selector: #selector(processorStartedEnhancing(_:)),
|
||||||
object: processor)
|
name: Notification.Name.blockProcessorStartedEnhancing,
|
||||||
|
object: processor
|
||||||
|
)
|
||||||
|
|
||||||
center.addObserver(self,
|
center.addObserver(
|
||||||
selector: #selector(processorStartedFetching(_:)),
|
self,
|
||||||
name: Notification.Name.blockProcessorStartedFetching,
|
selector: #selector(processorStartedFetching(_:)),
|
||||||
object: processor)
|
name: Notification.Name.blockProcessorStartedFetching,
|
||||||
|
object: processor
|
||||||
|
)
|
||||||
|
|
||||||
center.addObserver(self,
|
center.addObserver(
|
||||||
selector: #selector(processorStopped(_:)),
|
self,
|
||||||
name: Notification.Name.blockProcessorStopped,
|
selector: #selector(processorStopped(_:)),
|
||||||
object: processor)
|
name: Notification.Name.blockProcessorStopped,
|
||||||
|
object: processor
|
||||||
|
)
|
||||||
|
|
||||||
center.addObserver(self, selector: #selector(processorFailed(_:)),
|
center.addObserver(
|
||||||
name: Notification.Name.blockProcessorFailed,
|
self,
|
||||||
object: processor)
|
selector: #selector(processorFailed(_:)),
|
||||||
|
name: Notification.Name.blockProcessorFailed,
|
||||||
|
object: processor
|
||||||
|
)
|
||||||
|
|
||||||
center.addObserver(self,
|
center.addObserver(
|
||||||
selector: #selector(processorIdle(_:)),
|
self,
|
||||||
name: Notification.Name.blockProcessorIdle,
|
selector: #selector(processorIdle(_:)),
|
||||||
object: processor)
|
name: Notification.Name.blockProcessorIdle,
|
||||||
|
object: processor
|
||||||
|
)
|
||||||
|
|
||||||
center.addObserver(self,
|
center.addObserver(
|
||||||
selector: #selector(processorFinished(_:)),
|
self,
|
||||||
name: Notification.Name.blockProcessorFinished,
|
selector: #selector(processorFinished(_:)),
|
||||||
object: processor)
|
name: Notification.Name.blockProcessorFinished,
|
||||||
|
object: processor
|
||||||
|
)
|
||||||
|
|
||||||
center.addObserver(self,
|
center.addObserver(
|
||||||
selector: #selector(processorTransitionUnknown(_:)),
|
self,
|
||||||
name: Notification.Name.blockProcessorUnknownTransition,
|
selector: #selector(processorTransitionUnknown(_:)),
|
||||||
object: processor)
|
name: Notification.Name.blockProcessorUnknownTransition,
|
||||||
|
object: processor
|
||||||
|
)
|
||||||
|
|
||||||
center.addObserver(self,
|
center.addObserver(
|
||||||
selector: #selector(reorgDetected(_:)),
|
self,
|
||||||
name: Notification.Name.blockProcessorHandledReOrg,
|
selector: #selector(reorgDetected(_:)),
|
||||||
object: processor)
|
name: Notification.Name.blockProcessorHandledReOrg,
|
||||||
|
object: processor
|
||||||
|
)
|
||||||
|
|
||||||
center.addObserver(self,
|
center.addObserver(
|
||||||
selector: #selector(transactionsFound(_:)),
|
self,
|
||||||
name: Notification.Name.blockProcessorFoundTransactions,
|
selector: #selector(transactionsFound(_:)),
|
||||||
object: processor)
|
name: Notification.Name.blockProcessorFoundTransactions,
|
||||||
|
object: processor
|
||||||
|
)
|
||||||
|
|
||||||
center.addObserver(self,
|
center.addObserver(
|
||||||
selector: #selector(connectivityStateChanged(_:)),
|
self,
|
||||||
name: Notification.Name.blockProcessorConnectivityStateChanged,
|
selector: #selector(connectivityStateChanged(_:)),
|
||||||
object: nil)
|
name: Notification.Name.blockProcessorConnectivityStateChanged,
|
||||||
|
object: nil
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Block Processor notifications
|
// MARK: Block Processor notifications
|
||||||
|
@ -304,9 +332,10 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
name: .synchronizerConnectionStateChanged,
|
name: .synchronizerConnectionStateChanged,
|
||||||
object: self,
|
object: self,
|
||||||
userInfo: [
|
userInfo: [
|
||||||
NotificationKeys.previousConnectionState : ConnectionState(previous),
|
NotificationKeys.previousConnectionState: ConnectionState(previous),
|
||||||
NotificationKeys.currentConnectionState : currentState
|
NotificationKeys.currentConnectionState: currentState
|
||||||
])
|
]
|
||||||
|
)
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
self?.connectionState = currentState
|
self?.connectionState = currentState
|
||||||
|
@ -318,7 +347,13 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
let foundTransactions = userInfo[CompactBlockProcessorNotificationKey.foundTransactions] as? [ConfirmedTransactionEntity] else {
|
let foundTransactions = userInfo[CompactBlockProcessorNotificationKey.foundTransactions] as? [ConfirmedTransactionEntity] else {
|
||||||
return
|
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) {
|
@objc func reorgDetected(_ notification: Notification) {
|
||||||
|
@ -388,14 +423,16 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func processorFailed(_ notification: Notification) {
|
@objc func processorFailed(_ notification: Notification) {
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
if let error = notification.userInfo?[CompactBlockProcessorNotificationKey.error] as? Error {
|
if let error = notification.userInfo?[CompactBlockProcessorNotificationKey.error] as? Error {
|
||||||
self.notifyFailure(error)
|
self.notifyFailure(error)
|
||||||
self.status = .error(self.mapError(error))
|
self.status = .error(self.mapError(error))
|
||||||
} else {
|
} 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"))
|
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
|
// MARK: Synchronizer methods
|
||||||
|
// 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) {
|
public func sendToAddress(
|
||||||
|
spendingKey: String,
|
||||||
|
zatoshi: Int64,
|
||||||
|
toAddress: String,
|
||||||
|
memo: String?,
|
||||||
|
from accountIndex: Int,
|
||||||
|
resultBlock: @escaping (Result<PendingTransactionEntity, Error>
|
||||||
|
) -> Void) {
|
||||||
initializer.downloadParametersIfNeeded { (downloadResult) in
|
initializer.downloadParametersIfNeeded { (downloadResult) in
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
switch downloadResult {
|
switch downloadResult {
|
||||||
case .success:
|
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):
|
case .failure(let error):
|
||||||
resultBlock(.failure(SynchronizerError.parameterMissing(underlyingError: 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's see if there are funds to shield
|
||||||
let derivationTool = DerivationTool(networkType: self.network.networkType)
|
let derivationTool = DerivationTool(networkType: self.network.networkType)
|
||||||
|
|
||||||
|
@ -455,8 +510,8 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
resultBlock(.failure(ShieldFundsError.insuficientTransparentFunds))
|
resultBlock(.failure(ShieldFundsError.insuficientTransparentFunds))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let vk = try derivationTool.deriveViewingKey(spendingKey: spendingKey)
|
let viewingKey = try derivationTool.deriveViewingKey(spendingKey: spendingKey)
|
||||||
let zAddr = try derivationTool.deriveShieldedAddress(viewingKey: vk)
|
let zAddr = try derivationTool.deriveShieldedAddress(viewingKey: viewingKey)
|
||||||
|
|
||||||
let shieldingSpend = try transactionManager.initSpend(zatoshi: Int(tBalance.verified), toAddress: zAddr, memo: memo, from: 0)
|
let shieldingSpend = try transactionManager.initSpend(zatoshi: Int(tBalance.verified), toAddress: zAddr, memo: memo, from: 0)
|
||||||
|
|
||||||
|
@ -564,7 +619,7 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
return
|
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 }
|
guard let self = self else { return }
|
||||||
switch r {
|
switch r {
|
||||||
case .success(let utxos):
|
case .success(let utxos):
|
||||||
|
@ -720,7 +775,7 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
let latestHeight = try transactionRepository.lastScannedHeight()
|
let latestHeight = try transactionRepository.lastScannedHeight()
|
||||||
|
|
||||||
try transactionManager.allPendingTransactions()?.filter( {
|
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( {
|
).forEach( {
|
||||||
try transactionManager.delete(pendingTransaction: $0)
|
try transactionManager.delete(pendingTransaction: $0)
|
||||||
} )
|
} )
|
||||||
|
|
|
@ -45,8 +45,8 @@ public class SaplingParameterDownloader {
|
||||||
|
|
||||||
private static func downloadFileWithRequest(_ request: URLRequest, at destination: URL, result: @escaping (Result<URL,Error>) -> Void) {
|
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
|
let task = URLSession.shared.downloadTask(with: request) { (url, _, error) in
|
||||||
if let e = error {
|
if let error = error {
|
||||||
result(.failure(Errors.failed(error: e)))
|
result(.failure(Errors.failed(error: error)))
|
||||||
return
|
return
|
||||||
} else if let localUrl = url {
|
} else if let localUrl = url {
|
||||||
do {
|
do {
|
||||||
|
@ -110,10 +110,10 @@ public class SaplingParameterDownloader {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static var spendParamsURLString: String {
|
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 {
|
public static var outputParamsURLString: String {
|
||||||
return ZcashSDK.CLOUD_PARAM_DIR_URL + ZcashSDK.OUTPUT_PARAM_FILE_NAME
|
return ZcashSDK.cloudParameterURL + ZcashSDK.outputParamFilename
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,14 +28,14 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
|
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
|
||||||
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
|
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
|
||||||
let downloader = CompactBlockDownloader(service: service, storage: repository)
|
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()
|
var info = LightdInfo()
|
||||||
info.blockHeight = 130000
|
info.blockHeight = 130000
|
||||||
info.branch = "d34db33f"
|
info.branch = "d34db33f"
|
||||||
info.chainName = "main"
|
info.chainName = "main"
|
||||||
info.buildUser = "test user"
|
info.buildUser = "test user"
|
||||||
info.consensusBranchID = "d34db33f"
|
info.consensusBranchID = "d34db33f"
|
||||||
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockRust = MockRustBackend.self
|
||||||
|
@ -68,14 +68,14 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
|
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
|
||||||
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
|
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
|
||||||
let downloader = CompactBlockDownloader(service: service, storage: repository)
|
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()
|
var info = LightdInfo()
|
||||||
info.blockHeight = 130000
|
info.blockHeight = 130000
|
||||||
info.branch = "d34db33f"
|
info.branch = "d34db33f"
|
||||||
info.chainName = "test"
|
info.chainName = "test"
|
||||||
info.buildUser = "test user"
|
info.buildUser = "test user"
|
||||||
info.consensusBranchID = "d34db4d"
|
info.consensusBranchID = "d34db4d"
|
||||||
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockRust = MockRustBackend.self
|
||||||
|
@ -109,14 +109,14 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
|
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
|
||||||
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
|
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
|
||||||
let downloader = CompactBlockDownloader(service: service, storage: repository)
|
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()
|
var info = LightdInfo()
|
||||||
info.blockHeight = 130000
|
info.blockHeight = 130000
|
||||||
info.branch = "d34db33f"
|
info.branch = "d34db33f"
|
||||||
info.chainName = "another"
|
info.chainName = "another"
|
||||||
info.buildUser = "test user"
|
info.buildUser = "test user"
|
||||||
info.consensusBranchID = "d34db4d"
|
info.consensusBranchID = "d34db4d"
|
||||||
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockRust = MockRustBackend.self
|
||||||
|
@ -149,7 +149,7 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
|
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
|
||||||
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
|
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
|
||||||
let downloader = CompactBlockDownloader(service: service, storage: repository)
|
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()
|
var info = LightdInfo()
|
||||||
info.blockHeight = 130000
|
info.blockHeight = 130000
|
||||||
info.branch = "d34db33f"
|
info.branch = "d34db33f"
|
||||||
|
@ -171,7 +171,7 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
operation.errorHandler = { error in
|
operation.errorHandler = { error in
|
||||||
expectation.fulfill()
|
expectation.fulfill()
|
||||||
switch error {
|
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
|
break
|
||||||
default:
|
default:
|
||||||
XCTFail("Expected CompactBlockProcessorError.saplingActivationMismatch but found \(error)")
|
XCTFail("Expected CompactBlockProcessorError.saplingActivationMismatch but found \(error)")
|
||||||
|
@ -193,14 +193,14 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
let expectedResult = FigureNextBatchOperation.NextState.wait(latestHeight: expectedLatestHeight, latestDownloadHeight: expectedLatestHeight)
|
let expectedResult = FigureNextBatchOperation.NextState.wait(latestHeight: expectedLatestHeight, latestDownloadHeight: expectedLatestHeight)
|
||||||
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
|
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
|
||||||
let downloader = CompactBlockDownloader(service: service, storage: repository)
|
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()
|
var info = LightdInfo()
|
||||||
info.blockHeight = UInt64(expectedLatestHeight)
|
info.blockHeight = UInt64(expectedLatestHeight)
|
||||||
info.branch = "d34db33f"
|
info.branch = "d34db33f"
|
||||||
info.chainName = "main"
|
info.chainName = "main"
|
||||||
info.buildUser = "test user"
|
info.buildUser = "test user"
|
||||||
info.consensusBranchID = "d34db4d"
|
info.consensusBranchID = "d34db4d"
|
||||||
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
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 expectedResult = FigureNextBatchOperation.NextState.processNewBlocks(range: CompactBlockProcessor.nextBatchBlockRange(latestHeight: expectedLatestHeight, latestDownloadedHeight: expectedStoreLatestHeight, walletBirthday: walletBirthday))
|
||||||
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
|
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
|
||||||
let downloader = CompactBlockDownloader(service: service, storage: repository)
|
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()
|
var info = LightdInfo()
|
||||||
info.blockHeight = UInt64(expectedLatestHeight)
|
info.blockHeight = UInt64(expectedLatestHeight)
|
||||||
info.branch = "d34db33f"
|
info.branch = "d34db33f"
|
||||||
info.chainName = "main"
|
info.chainName = "main"
|
||||||
info.buildUser = "test user"
|
info.buildUser = "test user"
|
||||||
info.consensusBranchID = "d34db4d"
|
info.consensusBranchID = "d34db4d"
|
||||||
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockRust = MockRustBackend.self
|
||||||
|
@ -307,14 +307,14 @@ class BlockBatchValidationTests: XCTestCase {
|
||||||
let expectedResult = FigureNextBatchOperation.NextState.finishProcessing(height: expectedStoreLatestHeight)
|
let expectedResult = FigureNextBatchOperation.NextState.finishProcessing(height: expectedStoreLatestHeight)
|
||||||
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
|
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
|
||||||
let downloader = CompactBlockDownloader(service: service, storage: repository)
|
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()
|
var info = LightdInfo()
|
||||||
info.blockHeight = UInt64(expectedLatestHeight)
|
info.blockHeight = UInt64(expectedLatestHeight)
|
||||||
info.branch = "d34db33f"
|
info.branch = "d34db33f"
|
||||||
info.chainName = "main"
|
info.chainName = "main"
|
||||||
info.buildUser = "test user"
|
info.buildUser = "test user"
|
||||||
info.consensusBranchID = "d34db4d"
|
info.consensusBranchID = "d34db4d"
|
||||||
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
|
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
|
||||||
service.mockLightDInfo = info
|
service.mockLightDInfo = info
|
||||||
|
|
||||||
let mockRust = MockRustBackend.self
|
let mockRust = MockRustBackend.self
|
||||||
|
|
|
@ -40,8 +40,8 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
|
|
||||||
let expect = XCTestExpectation(description: self.description)
|
let expect = XCTestExpectation(description: self.description)
|
||||||
expect.expectedFulfillmentCount = 3
|
expect.expectedFulfillmentCount = 3
|
||||||
let lowerRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT
|
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
|
||||||
let upperRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT + 99
|
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
|
||||||
|
|
||||||
let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange))
|
let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange))
|
||||||
downloader.downloadBlockRange(range) { (error) in
|
downloader.downloadBlockRange(range) { (error) in
|
||||||
|
@ -66,8 +66,8 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
|
|
||||||
func testSmallDownload() {
|
func testSmallDownload() {
|
||||||
|
|
||||||
let lowerRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT
|
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
|
||||||
let upperRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT + 99
|
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
|
||||||
|
|
||||||
let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange))
|
let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange))
|
||||||
var latest: BlockHeight = 0
|
var latest: BlockHeight = 0
|
||||||
|
@ -94,12 +94,12 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFailure() {
|
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)
|
let expect = XCTestExpectation(description: self.description)
|
||||||
expect.expectedFulfillmentCount = 1
|
expect.expectedFulfillmentCount = 1
|
||||||
let lowerRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT
|
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
|
||||||
let upperRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT + 99
|
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
|
||||||
|
|
||||||
let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange))
|
let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange))
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ class BlockScanOperationTests: XCTestCase {
|
||||||
let latestScannedBlockExpect = XCTestExpectation(description: self.description + "latestScannedHeight")
|
let latestScannedBlockExpect = XCTestExpectation(description: self.description + "latestScannedHeight")
|
||||||
let service = LightWalletGRPCService(endpoint: LightWalletEndpoint(address: "lightwalletd.testnet.electriccoin.co", port: 9067))
|
let service = LightWalletGRPCService(endpoint: LightWalletEndpoint(address: "lightwalletd.testnet.electriccoin.co", port: 9067))
|
||||||
let blockCount = 100
|
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 downloadOperation = CompactBlockDownloadOperation(downloader: CompactBlockDownloader.sqlDownloader(service: service, at: cacheDbURL)!, range: range)
|
||||||
let scanOperation = CompactBlockScanningOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL, networkType: network.networkType)
|
let scanOperation = CompactBlockScanningOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL, networkType: network.networkType)
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
class CompactBlockProcessorTests: XCTestCase {
|
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 processor: CompactBlockProcessor!
|
||||||
var downloadStartedExpect: XCTestExpectation!
|
var downloadStartedExpect: XCTestExpectation!
|
||||||
var updatedNotificationExpectation: XCTestExpectation!
|
var updatedNotificationExpectation: XCTestExpectation!
|
||||||
|
@ -19,7 +19,7 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
var startedValidatingNotificationExpectation: XCTestExpectation!
|
var startedValidatingNotificationExpectation: XCTestExpectation!
|
||||||
var idleNotificationExpectation: XCTestExpectation!
|
var idleNotificationExpectation: XCTestExpectation!
|
||||||
let network = ZcashNetworkBuilder.network(for: .testnet)
|
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 {
|
override func setUpWithError() throws {
|
||||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
// 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.chainName = "test"
|
||||||
info.consensusBranchID = branchID.toString()
|
info.consensusBranchID = branchID.toString()
|
||||||
info.estimatedHeight = UInt64(mockLatestHeight)
|
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))
|
let storage = CompactBlockStorage.init(connectionProvider: SimpleConnectionProvider(path: processorConfig.cacheDb.absoluteString))
|
||||||
|
@ -123,15 +123,15 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
|
|
||||||
// test first range
|
// test first range
|
||||||
var latestDownloadedHeight = processorConfig.walletBirthday // this can be either this or Wallet Birthday.
|
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))
|
var expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight, upper:latestBlockchainHeight))
|
||||||
|
|
||||||
XCTAssertEqual(expectedBatchRange, CompactBlockProcessor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight, walletBirthday: processorConfig.walletBirthday))
|
XCTAssertEqual(expectedBatchRange, CompactBlockProcessor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight, walletBirthday: processorConfig.walletBirthday))
|
||||||
|
|
||||||
// Test mid-range
|
// Test mid-range
|
||||||
latestDownloadedHeight = BlockHeight(network.constants.SAPLING_ACTIVATION_HEIGHT + ZcashSDK.DEFAULT_BATCH_SIZE)
|
latestDownloadedHeight = BlockHeight(network.constants.saplingActivationHeight + ZcashSDK.DefaultBatchSize)
|
||||||
latestBlockchainHeight = BlockHeight(network.constants.SAPLING_ACTIVATION_HEIGHT + 1000)
|
latestBlockchainHeight = BlockHeight(network.constants.saplingActivationHeight + 1000)
|
||||||
|
|
||||||
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))
|
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))
|
||||||
|
|
||||||
|
@ -139,8 +139,8 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
|
|
||||||
// Test last batch range
|
// Test last batch range
|
||||||
|
|
||||||
latestDownloadedHeight = BlockHeight(network.constants.SAPLING_ACTIVATION_HEIGHT + 950)
|
latestDownloadedHeight = BlockHeight(network.constants.saplingActivationHeight + 950)
|
||||||
latestBlockchainHeight = BlockHeight(network.constants.SAPLING_ACTIVATION_HEIGHT + 1000)
|
latestBlockchainHeight = BlockHeight(network.constants.saplingActivationHeight + 1000)
|
||||||
|
|
||||||
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))
|
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import XCTest
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
class CompactBlockReorgTests: XCTestCase {
|
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 processor: CompactBlockProcessor!
|
||||||
var downloadStartedExpect: XCTestExpectation!
|
var downloadStartedExpect: XCTestExpectation!
|
||||||
var updatedNotificationExpectation: XCTestExpectation!
|
var updatedNotificationExpectation: XCTestExpectation!
|
||||||
|
@ -21,7 +21,7 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
var idleNotificationExpectation: XCTestExpectation!
|
var idleNotificationExpectation: XCTestExpectation!
|
||||||
var reorgNotificationExpectation: XCTestExpectation!
|
var reorgNotificationExpectation: XCTestExpectation!
|
||||||
let network = ZcashNetworkBuilder.network(for: .testnet)
|
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 {
|
override func setUpWithError() throws {
|
||||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
// 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.chainName = "test"
|
||||||
info.consensusBranchID = branchID.toString()
|
info.consensusBranchID = branchID.toString()
|
||||||
info.estimatedHeight = UInt64(mockLatestHeight)
|
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)
|
try ZcashRustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: .testnet)
|
||||||
|
@ -49,7 +49,7 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
let mockBackend = MockRustBackend.self
|
let mockBackend = MockRustBackend.self
|
||||||
mockBackend.mockValidateCombinedChainFailAfterAttempts = 3
|
mockBackend.mockValidateCombinedChainFailAfterAttempts = 3
|
||||||
mockBackend.mockValidateCombinedChainKeepFailing = false
|
mockBackend.mockValidateCombinedChainKeepFailing = false
|
||||||
mockBackend.mockValidateCombinedChainFailureHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT + 320
|
mockBackend.mockValidateCombinedChainFailureHeight = self.network.constants.saplingActivationHeight + 320
|
||||||
|
|
||||||
processor = CompactBlockProcessor(service: service,
|
processor = CompactBlockProcessor(service: service,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
|
@ -86,8 +86,8 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
XCTAssertNotNil(notification.userInfo)
|
XCTAssertNotNil(notification.userInfo)
|
||||||
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
|
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
|
||||||
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
|
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
|
||||||
XCTAssertTrue( reorg == 0 || reorg > self.network.constants.SAPLING_ACTIVATION_HEIGHT)
|
XCTAssertTrue( reorg == 0 || reorg > self.network.constants.saplingActivationHeight)
|
||||||
XCTAssertTrue( rewind == 0 || rewind > self.network.constants.SAPLING_ACTIVATION_HEIGHT)
|
XCTAssertTrue( rewind == 0 || rewind > self.network.constants.saplingActivationHeight)
|
||||||
XCTAssertTrue( rewind <= reorg )
|
XCTAssertTrue( rewind <= reorg )
|
||||||
reorgNotificationExpectation.fulfill()
|
reorgNotificationExpectation.fulfill()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -20,7 +20,7 @@ class CompactBlockStorageTests: XCTestCase {
|
||||||
|
|
||||||
func testStoreThousandBlocks() {
|
func testStoreThousandBlocks() {
|
||||||
let initialHeight = try! compactBlockDao.latestHeight()
|
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 blockCount = Int(1_000)
|
||||||
let finalHeight = startHeight + blockCount
|
let finalHeight = startHeight + blockCount
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ class CompactBlockStorageTests: XCTestCase {
|
||||||
|
|
||||||
func testRewindTo() {
|
func testRewindTo() {
|
||||||
|
|
||||||
let startHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT
|
let startHeight = self.network.constants.saplingActivationHeight
|
||||||
let blockCount = Int(1_000)
|
let blockCount = Int(1_000)
|
||||||
let finalHeight = startHeight + blockCount
|
let finalHeight = startHeight + blockCount
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ class DownloadOperationTests: XCTestCase {
|
||||||
let storage = try! TestDbBuilder.inMemoryCompactBlockStorage()
|
let storage = try! TestDbBuilder.inMemoryCompactBlockStorage()
|
||||||
let downloader = CompactBlockDownloader(service: service, storage: storage)
|
let downloader = CompactBlockDownloader(service: service, storage: storage)
|
||||||
let blockCount = 100
|
let blockCount = 100
|
||||||
let activationHeight = network.constants.SAPLING_ACTIVATION_HEIGHT
|
let activationHeight = network.constants.saplingActivationHeight
|
||||||
let range = activationHeight ... activationHeight + blockCount
|
let range = activationHeight ... activationHeight + blockCount
|
||||||
let downloadOperation = CompactBlockDownloadOperation(downloader: downloader, range: range)
|
let downloadOperation = CompactBlockDownloadOperation(downloader: downloader, range: range)
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,8 @@ class LightWalletServiceTests: XCTestCase {
|
||||||
func testHundredBlocks() {
|
func testHundredBlocks() {
|
||||||
let expect = XCTestExpectation(description: self.description)
|
let expect = XCTestExpectation(description: self.description)
|
||||||
let count = 99
|
let count = 99
|
||||||
let lowerRange: BlockHeight = network.constants.SAPLING_ACTIVATION_HEIGHT
|
let lowerRange: BlockHeight = network.constants.saplingActivationHeight
|
||||||
let upperRange: BlockHeight = network.constants.SAPLING_ACTIVATION_HEIGHT + count
|
let upperRange: BlockHeight = network.constants.saplingActivationHeight + count
|
||||||
let blockRange = lowerRange ... upperRange
|
let blockRange = lowerRange ... upperRange
|
||||||
|
|
||||||
service.blockRange(blockRange) { (result) in
|
service.blockRange(blockRange) { (result) in
|
||||||
|
@ -61,8 +61,8 @@ class LightWalletServiceTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSyncBlockRange() {
|
func testSyncBlockRange() {
|
||||||
let lowerRange: BlockHeight = network.constants.SAPLING_ACTIVATION_HEIGHT
|
let lowerRange: BlockHeight = network.constants.saplingActivationHeight
|
||||||
let upperRange: BlockHeight = network.constants.SAPLING_ACTIVATION_HEIGHT + 99
|
let upperRange: BlockHeight = network.constants.saplingActivationHeight + 99
|
||||||
let blockRange = lowerRange ... upperRange
|
let blockRange = lowerRange ... upperRange
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -81,7 +81,7 @@ class LightWalletServiceTests: XCTestCase {
|
||||||
case .failure(let e):
|
case .failure(let e):
|
||||||
XCTFail("error: \(e)")
|
XCTFail("error: \(e)")
|
||||||
case .success(let height):
|
case .success(let height):
|
||||||
XCTAssertTrue(height > self.network.constants.SAPLING_ACTIVATION_HEIGHT)
|
XCTAssertTrue(height > self.network.constants.saplingActivationHeight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ class NetworkUpgradeTests: XCTestCase {
|
||||||
|
|
||||||
let firstSyncExpectation = XCTestExpectation(description: "first sync")
|
let firstSyncExpectation = XCTestExpectation(description: "first sync")
|
||||||
|
|
||||||
try coordinator.applyStaged(blockheight: activationHeight - ZcashSDK.DEFAULT_STALE_TOLERANCE)
|
try coordinator.applyStaged(blockheight: activationHeight - ZcashSDK.defaultStaleTolerance)
|
||||||
sleep(5)
|
sleep(5)
|
||||||
|
|
||||||
try coordinator.sync(completion: { (synchronizer) in
|
try coordinator.sync(completion: { (synchronizer) in
|
||||||
|
|
|
@ -286,8 +286,8 @@ class TestSynchronizerBuilder {
|
||||||
dataDb: initializer.dataDbURL,
|
dataDb: initializer.dataDbURL,
|
||||||
downloadBatchSize: 100,
|
downloadBatchSize: 100,
|
||||||
retries: 5,
|
retries: 5,
|
||||||
maxBackoffInterval: ZcashSDK.DEFAULT_MAX_BACKOFF_INTERVAL,
|
maxBackoffInterval: ZcashSDK.defaultMaxBackOffInterval,
|
||||||
rewindDistance: ZcashSDK.DEFAULT_REWIND_DISTANCE,
|
rewindDistance: ZcashSDK.defaultRewindDistance,
|
||||||
walletBirthday: walletBirthday.height,
|
walletBirthday: walletBirthday.height,
|
||||||
saplingActivation: lowerBoundHeight,
|
saplingActivation: lowerBoundHeight,
|
||||||
network: network)
|
network: network)
|
||||||
|
|
|
@ -202,31 +202,30 @@ class DarksideWalletService: LightWalletService {
|
||||||
|
|
||||||
|
|
||||||
class DarksideWalletDConstants: NetworkConstants {
|
class DarksideWalletDConstants: NetworkConstants {
|
||||||
static var SAPLING_ACTIVATION_HEIGHT: BlockHeight {
|
|
||||||
|
static var saplingActivationHeight: BlockHeight {
|
||||||
663150
|
663150
|
||||||
}
|
}
|
||||||
|
|
||||||
static var DEFAULT_DATA_DB_NAME: String {
|
static var defaultDataDbName: String {
|
||||||
ZcashSDKMainnetConstants.DEFAULT_DATA_DB_NAME
|
ZcashSDKMainnetConstants.defaultDataDbName
|
||||||
}
|
}
|
||||||
|
|
||||||
static var DEFAULT_CACHES_DB_NAME: String {
|
static var defaultCacheDbName: String {
|
||||||
ZcashSDKMainnetConstants.DEFAULT_CACHES_DB_NAME
|
ZcashSDKMainnetConstants.defaultCacheDbName
|
||||||
}
|
}
|
||||||
|
|
||||||
static var DEFAULT_PENDING_DB_NAME: String {
|
static var defaultPendingDbName: String {
|
||||||
ZcashSDKMainnetConstants.DEFAULT_PENDING_DB_NAME
|
ZcashSDKMainnetConstants.defaultPendingDbName
|
||||||
}
|
}
|
||||||
|
|
||||||
static var DEFAULT_DB_NAME_PREFIX: String {
|
static var defaultDbNamePrefix: String {
|
||||||
ZcashSDKMainnetConstants.DEFAULT_DB_NAME_PREFIX
|
ZcashSDKMainnetConstants.defaultDbNamePrefix
|
||||||
}
|
}
|
||||||
|
|
||||||
static var FEE_CHANGE_HEIGHT: BlockHeight {
|
static var feeChangeHeight: BlockHeight {
|
||||||
ZcashSDKMainnetConstants.FEE_CHANGE_HEIGHT
|
ZcashSDKMainnetConstants.feeChangeHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
class DarksideWalletDNetwork: ZcashNetwork {
|
class DarksideWalletDNetwork: ZcashNetwork {
|
||||||
var constants: NetworkConstants.Type = DarksideWalletDConstants.self
|
var constants: NetworkConstants.Type = DarksideWalletDConstants.self
|
||||||
|
|
|
@ -79,7 +79,7 @@ class FakeChainBuilder {
|
||||||
|
|
||||||
try darksideWallet.useDataset(testnetCanopyStartBlock)
|
try darksideWallet.useDataset(testnetCanopyStartBlock)
|
||||||
try darksideWallet.stageBlocksCreate(from: birthday + 1, count: length)
|
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 {
|
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 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)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,16 +144,16 @@ class MockTransactionRepository: TransactionRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
func mockSent(_ index: Int) -> ConfirmedTransactionEntity {
|
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 {
|
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 {
|
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 {
|
func randomTimeInterval() -> TimeInterval {
|
||||||
Double.random(in: Date().timeIntervalSince1970 - 1000000.0 ... Date().timeIntervalSince1970)
|
Double.random(in: Date().timeIntervalSince1970 - 1000000.0 ... Date().timeIntervalSince1970)
|
||||||
|
|
|
@ -322,7 +322,7 @@ class MockRustBackend: ZcashRustBackendWelding {
|
||||||
nil
|
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
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue