Error handling refactor (#170)
* Improve error handling on processor and service * Error Refactoring * fix XCode12 issue * Fix Compilation errors and test * bump MIDDLE version
This commit is contained in:
parent
b214a19724
commit
251b4c7aa3
|
@ -6,7 +6,7 @@ target 'ZcashLightClientSample' do
|
||||||
pod "KRProgressHUD"
|
pod "KRProgressHUD"
|
||||||
# Pods for ZcashLightClientSample
|
# Pods for ZcashLightClientSample
|
||||||
pod 'ZcashLightClientKit', :path => '../../', :testspecs => ['Tests']
|
pod 'ZcashLightClientKit', :path => '../../', :testspecs => ['Tests']
|
||||||
pod 'gRPC-Swift', '~> 1.0.0-alpha.11'
|
pod 'gRPC-Swift', '= 1.0.0-alpha.17'
|
||||||
pod 'PaginatedTableView'
|
pod 'PaginatedTableView'
|
||||||
pod 'NotificationBubbles'
|
pod 'NotificationBubbles'
|
||||||
pod 'MnemonicSwift'
|
pod 'MnemonicSwift'
|
||||||
|
|
|
@ -1,78 +1,78 @@
|
||||||
PODS:
|
PODS:
|
||||||
- CGRPCZlib (1.0.0-alpha.14)
|
- CGRPCZlib (1.0.0-alpha.17)
|
||||||
- CNIOAtomics (2.18.0)
|
- CNIOAtomics (2.20.2)
|
||||||
- CNIOBoringSSL (2.7.4)
|
- CNIOBoringSSL (2.9.0)
|
||||||
- CNIOBoringSSLShims (2.7.4):
|
- CNIOBoringSSLShims (2.9.0):
|
||||||
- CNIOBoringSSL (= 2.7.4)
|
- CNIOBoringSSL (= 2.9.0)
|
||||||
- CNIODarwin (2.18.0)
|
- CNIODarwin (2.20.2)
|
||||||
- CNIOHTTPParser (2.18.0)
|
- CNIOHTTPParser (2.20.2)
|
||||||
- CNIOLinux (2.18.0)
|
- CNIOLinux (2.20.2)
|
||||||
- CNIOSHA1 (2.18.0)
|
- CNIOSHA1 (2.20.2)
|
||||||
- gRPC-Swift (1.0.0-alpha.14):
|
- gRPC-Swift (1.0.0-alpha.17):
|
||||||
- CGRPCZlib (= 1.0.0-alpha.14)
|
- CGRPCZlib (= 1.0.0-alpha.17)
|
||||||
- Logging (< 2, >= 1.2.0)
|
- Logging (< 2, >= 1.2.0)
|
||||||
- SwiftNIO (< 3, >= 2.18.0)
|
- SwiftNIO (< 3, >= 2.19.0)
|
||||||
- SwiftNIOHTTP2 (< 2, >= 1.12.2)
|
- SwiftNIOHTTP2 (< 2, >= 1.12.2)
|
||||||
- SwiftNIOSSL (< 3, >= 2.7.4)
|
- SwiftNIOSSL (< 3, >= 2.8.0)
|
||||||
- SwiftNIOTransportServices (< 2, >= 1.6.0)
|
- SwiftNIOTransportServices (< 2, >= 1.6.0)
|
||||||
- SwiftProtobuf (< 2, >= 1.9.0)
|
- SwiftProtobuf (< 2, >= 1.9.0)
|
||||||
- KRActivityIndicatorView (3.0.5)
|
- KRActivityIndicatorView (3.0.5)
|
||||||
- KRProgressHUD (3.4.5):
|
- KRProgressHUD (3.4.5):
|
||||||
- KRActivityIndicatorView (= 3.0.5)
|
- KRActivityIndicatorView (= 3.0.5)
|
||||||
- Logging (1.2.0)
|
- Logging (1.4.0)
|
||||||
- MnemonicSwift (1.0.0)
|
- MnemonicSwift (1.0.0)
|
||||||
- NotificationBubbles (0.1.1)
|
- NotificationBubbles (0.1.1)
|
||||||
- PaginatedTableView (1.0.1)
|
- PaginatedTableView (1.0.1)
|
||||||
- SQLite.swift (0.12.2):
|
- SQLite.swift (0.12.2):
|
||||||
- SQLite.swift/standard (= 0.12.2)
|
- SQLite.swift/standard (= 0.12.2)
|
||||||
- SQLite.swift/standard (0.12.2)
|
- SQLite.swift/standard (0.12.2)
|
||||||
- SwiftNIO (2.18.0):
|
- SwiftNIO (2.20.2):
|
||||||
- CNIOAtomics (= 2.18.0)
|
- CNIOAtomics (= 2.20.2)
|
||||||
- CNIODarwin (= 2.18.0)
|
- CNIODarwin (= 2.20.2)
|
||||||
- CNIOLinux (= 2.18.0)
|
- CNIOLinux (= 2.20.2)
|
||||||
- CNIOSHA1 (= 2.18.0)
|
- CNIOSHA1 (= 2.20.2)
|
||||||
- SwiftNIOConcurrencyHelpers (= 2.18.0)
|
- SwiftNIOConcurrencyHelpers (= 2.20.2)
|
||||||
- SwiftNIOConcurrencyHelpers (2.18.0):
|
- SwiftNIOConcurrencyHelpers (2.20.2):
|
||||||
- CNIOAtomics (= 2.18.0)
|
- CNIOAtomics (= 2.20.2)
|
||||||
- SwiftNIOFoundationCompat (2.18.0):
|
- SwiftNIOFoundationCompat (2.20.2):
|
||||||
- SwiftNIO (= 2.18.0)
|
- SwiftNIO (= 2.20.2)
|
||||||
- SwiftNIOHPACK (1.12.2):
|
- SwiftNIOHPACK (1.13.0):
|
||||||
- SwiftNIO (= 2.18.0)
|
- SwiftNIO (< 3, >= 2.19.0)
|
||||||
- SwiftNIOConcurrencyHelpers (= 2.18.0)
|
- SwiftNIOConcurrencyHelpers (< 3, >= 2.19.0)
|
||||||
- SwiftNIOHTTP1 (= 2.18.0)
|
- SwiftNIOHTTP1 (< 3, >= 2.19.0)
|
||||||
- SwiftNIOHTTP1 (2.18.0):
|
- SwiftNIOHTTP1 (2.20.2):
|
||||||
- CNIOHTTPParser (= 2.18.0)
|
- CNIOHTTPParser (= 2.20.2)
|
||||||
- SwiftNIO (= 2.18.0)
|
- SwiftNIO (= 2.20.2)
|
||||||
- SwiftNIOConcurrencyHelpers (= 2.18.0)
|
- SwiftNIOConcurrencyHelpers (= 2.20.2)
|
||||||
- SwiftNIOHTTP2 (1.12.2):
|
- SwiftNIOHTTP2 (1.13.0):
|
||||||
- SwiftNIO (= 2.18.0)
|
- SwiftNIO (< 3, >= 2.19.0)
|
||||||
- SwiftNIOConcurrencyHelpers (= 2.18.0)
|
- SwiftNIOConcurrencyHelpers (< 3, >= 2.19.0)
|
||||||
- SwiftNIOHPACK (= 1.12.2)
|
- SwiftNIOHPACK (= 1.13.0)
|
||||||
- SwiftNIOHTTP1 (= 2.18.0)
|
- SwiftNIOHTTP1 (< 3, >= 2.19.0)
|
||||||
- SwiftNIOTLS (= 2.18.0)
|
- SwiftNIOTLS (< 3, >= 2.19.0)
|
||||||
- SwiftNIOSSL (2.7.4):
|
- SwiftNIOSSL (2.9.0):
|
||||||
- CNIOBoringSSL (= 2.7.4)
|
- CNIOBoringSSL (= 2.9.0)
|
||||||
- CNIOBoringSSLShims (= 2.7.4)
|
- CNIOBoringSSLShims (= 2.9.0)
|
||||||
- SwiftNIO (= 2.18.0)
|
- SwiftNIO (< 3, >= 2.19.0)
|
||||||
- SwiftNIOConcurrencyHelpers (= 2.18.0)
|
- SwiftNIOConcurrencyHelpers (< 3, >= 2.19.0)
|
||||||
- SwiftNIOTLS (= 2.18.0)
|
- SwiftNIOTLS (< 3, >= 2.19.0)
|
||||||
- SwiftNIOTLS (2.18.0):
|
- SwiftNIOTLS (2.20.2):
|
||||||
- SwiftNIO (= 2.18.0)
|
- SwiftNIO (= 2.20.2)
|
||||||
- SwiftNIOTransportServices (1.6.0):
|
- SwiftNIOTransportServices (1.8.0):
|
||||||
- SwiftNIO (~> 2.0)
|
- SwiftNIO (< 3, >= 2.19.0)
|
||||||
- SwiftNIOConcurrencyHelpers (~> 2.0)
|
- SwiftNIOConcurrencyHelpers (< 3, >= 2.19.0)
|
||||||
- SwiftNIOFoundationCompat (~> 2.0)
|
- SwiftNIOFoundationCompat (< 3, >= 2.19.0)
|
||||||
- SwiftNIOTLS (~> 2.0)
|
- SwiftNIOTLS (< 3, >= 2.19.0)
|
||||||
- SwiftProtobuf (1.9.0)
|
- SwiftProtobuf (1.11.0)
|
||||||
- ZcashLightClientKit (0.5.3):
|
- ZcashLightClientKit (0.5.3):
|
||||||
- gRPC-Swift (~> 1.0.0-alpha.11)
|
- gRPC-Swift (~> 1.0.0-alpha.17)
|
||||||
- SQLite.swift (~> 0.12.2)
|
- SQLite.swift (~> 0.12.2)
|
||||||
- ZcashLightClientKit/Tests (0.5.3):
|
- ZcashLightClientKit/Tests (0.5.3):
|
||||||
- gRPC-Swift (~> 1.0.0-alpha.11)
|
- gRPC-Swift (~> 1.0.0-alpha.11, ~> 1.0.0-alpha.17)
|
||||||
- SQLite.swift (~> 0.12.2)
|
- SQLite.swift (~> 0.12.2)
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- gRPC-Swift (~> 1.0.0-alpha.11)
|
- gRPC-Swift (= 1.0.0-alpha.17)
|
||||||
- KRProgressHUD
|
- KRProgressHUD
|
||||||
- MnemonicSwift
|
- MnemonicSwift
|
||||||
- NotificationBubbles
|
- NotificationBubbles
|
||||||
|
@ -114,34 +114,34 @@ EXTERNAL SOURCES:
|
||||||
:path: "../../"
|
:path: "../../"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
CGRPCZlib: 06247b0687f3a3edbfbfb204d53721c3ba262a34
|
CGRPCZlib: 245283cd656bf0c309a48a887c27865d6f54f7ef
|
||||||
CNIOAtomics: b6053043649c8b9afbf2560d9d64899d5d7ce368
|
CNIOAtomics: 7daf6423d00650104436c5f8a2a341679104ae83
|
||||||
CNIOBoringSSL: 21bbd36e5a68c9d2ea1aea7bfea10eea60d25a82
|
CNIOBoringSSL: fb66746214b40dded1a8ddf2e078af0eff07bfb8
|
||||||
CNIOBoringSSLShims: e9e57b1fd0e060a25f2f3b0b944cc84dd272368f
|
CNIOBoringSSLShims: c7a6e1e29088739872e51f70f8305beadfa6ca61
|
||||||
CNIODarwin: 2e814fe13ee1b16a6d7603affbd95b3fbf1e65b1
|
CNIODarwin: 65509d8e6a65a3f3f7bf5b09455cbabd535f48f3
|
||||||
CNIOHTTPParser: 215fe669981deb6b7e4533b0b42a01e5c165d8ac
|
CNIOHTTPParser: ec6aa14852274b383a52bacd4d6bb3d2432a50e9
|
||||||
CNIOLinux: 45e91eaba50bb850a48135aabbd7671625f15188
|
CNIOLinux: 380e2601f1f32f8f32a78437c5f4f5a688205e2b
|
||||||
CNIOSHA1: f8f5b0c8cbd067c195d1b44ab237927765bd4914
|
CNIOSHA1: 5cc4fc5054beeb21c8e0017ad6bf559ce8095c10
|
||||||
gRPC-Swift: fb8ff0d8cdd5a020c170ba827f50c393ae31e307
|
gRPC-Swift: 871cf2df24d9f5424763ae5af7248ed26a1b1314
|
||||||
KRActivityIndicatorView: 912bc0413d98340f384b12a4e1e6aa8f42fb377d
|
KRActivityIndicatorView: 912bc0413d98340f384b12a4e1e6aa8f42fb377d
|
||||||
KRProgressHUD: df4cdc3a1baf708d4276a089ee34d133fa9a6f3e
|
KRProgressHUD: df4cdc3a1baf708d4276a089ee34d133fa9a6f3e
|
||||||
Logging: 7838d379d234d7e5ae1265fa02804a9084caf04c
|
Logging: beeb016c9c80cf77042d62e83495816847ef108b
|
||||||
MnemonicSwift: d743ec3dcc1cdce706a1876dba0b6250ad1ef90d
|
MnemonicSwift: d743ec3dcc1cdce706a1876dba0b6250ad1ef90d
|
||||||
NotificationBubbles: 91ee10deee54f35b5d49a161e1cb3d788ab5d011
|
NotificationBubbles: 91ee10deee54f35b5d49a161e1cb3d788ab5d011
|
||||||
PaginatedTableView: 294d9831d5ddf5c0dcfbb4a281d4fcfb8d12f55a
|
PaginatedTableView: 294d9831d5ddf5c0dcfbb4a281d4fcfb8d12f55a
|
||||||
SQLite.swift: d2b4642190917051ce6bd1d49aab565fe794eea3
|
SQLite.swift: d2b4642190917051ce6bd1d49aab565fe794eea3
|
||||||
SwiftNIO: c17d311e9006fc10c1d17fbc6a7a9cb21aa46368
|
SwiftNIO: a3c1b37da3e97ce44b3cfafc61c05fe0cac540b8
|
||||||
SwiftNIOConcurrencyHelpers: 69762a04ed76d7254012e1f17787ee162d2cf764
|
SwiftNIOConcurrencyHelpers: cd7afc3d1f1ceaf55bbd030e7d1a469d3024db92
|
||||||
SwiftNIOFoundationCompat: 9af7b2e265c4d55eb8599a515d63784c2691dc39
|
SwiftNIOFoundationCompat: 573f44d5b24f7ead54b6b111264c0a420fc6eccf
|
||||||
SwiftNIOHPACK: 871e4e893ecc1aeaf74435b73c13240f50d6853c
|
SwiftNIOHPACK: 0346ad2091511232c8cf19a6183b9c96ce33baf3
|
||||||
SwiftNIOHTTP1: 67eafb3f27c3aee867dc4c0ec947e2ab71f1e2ce
|
SwiftNIOHTTP1: b54fae8700b647e908597aa7ed3370389f634b87
|
||||||
SwiftNIOHTTP2: c7ce23b714868de63dae083478b40da20d933e08
|
SwiftNIOHTTP2: 8a0f333b99f9283f457762f58baa30acfee354cb
|
||||||
SwiftNIOSSL: 0f28ad98a39b4c625196c2c8f154a4fded66bd96
|
SwiftNIOSSL: 3e67b565a567c20ed38586ae0b3566f190776a95
|
||||||
SwiftNIOTLS: 78c6d6798ea29f7eb0a4e1214a00bc8f07e7390c
|
SwiftNIOTLS: 9225a214c2483873406322d83c9db3731d8350e9
|
||||||
SwiftNIOTransportServices: 775bcda101a0d921feb69d79b5884acfce0fc0f2
|
SwiftNIOTransportServices: e69704b2d41b68a531bf3aa0177fec81ba1361e6
|
||||||
SwiftProtobuf: ecbec1be9036d15655f6b3443a1c4ea693c97932
|
SwiftProtobuf: f889fe5772f90ef7d7b8aac352d1fddf39650713
|
||||||
ZcashLightClientKit: 45c910a419418feb081e53d179875f740091812e
|
ZcashLightClientKit: 52c03806e721784c91b87a2ab038ee302e1635b9
|
||||||
|
|
||||||
PODFILE CHECKSUM: 191070101f577589f53b033656190b612695c5f7
|
PODFILE CHECKSUM: 0055c060ebfda59d4243e428eedc1db06c245f19
|
||||||
|
|
||||||
COCOAPODS: 1.9.3
|
COCOAPODS: 1.9.3
|
||||||
|
|
|
@ -10,7 +10,7 @@ import Foundation
|
||||||
import ZcashLightClientKit
|
import ZcashLightClientKit
|
||||||
import os
|
import os
|
||||||
|
|
||||||
class SampleLogger: Logger {
|
class SampleLogger: ZcashLightClientKit.Logger {
|
||||||
enum LogLevel: Int {
|
enum LogLevel: Int {
|
||||||
case debug
|
case debug
|
||||||
case error
|
case error
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
Pod::Spec.new do |s|
|
Pod::Spec.new do |s|
|
||||||
s.name = 'ZcashLightClientKit'
|
s.name = 'ZcashLightClientKit'
|
||||||
s.version = '0.5.3'
|
s.version = '0.6.0'
|
||||||
s.summary = 'Zcash Light Client wallet SDK for iOS'
|
s.summary = 'Zcash Light Client wallet SDK for iOS'
|
||||||
|
|
||||||
s.description = <<-DESC
|
s.description = <<-DESC
|
||||||
|
@ -19,7 +19,7 @@ Pod::Spec.new do |s|
|
||||||
s.module_map = 'ZcashLightClientKit.modulemap'
|
s.module_map = 'ZcashLightClientKit.modulemap'
|
||||||
s.swift_version = '5.1'
|
s.swift_version = '5.1'
|
||||||
s.ios.deployment_target = '12.0'
|
s.ios.deployment_target = '12.0'
|
||||||
s.dependency 'gRPC-Swift', '~> 1.0.0-alpha.11'
|
s.dependency 'gRPC-Swift', '~> 1.0.0-alpha.17'
|
||||||
s.dependency 'SQLite.swift', '~> 0.12.2'
|
s.dependency 'SQLite.swift', '~> 0.12.2'
|
||||||
s.ios.vendored_libraries = 'lib/libzcashlc.a'
|
s.ios.vendored_libraries = 'lib/libzcashlc.a'
|
||||||
s.preserve_paths = ['Scripts', 'rust','docs','Cargo.*','ZcashLightClientKit/Stencil']
|
s.preserve_paths = ['Scripts', 'rust','docs','Cargo.*','ZcashLightClientKit/Stencil']
|
||||||
|
|
|
@ -16,10 +16,13 @@ public enum CompactBlockProcessorError: Error {
|
||||||
case invalidConfiguration
|
case invalidConfiguration
|
||||||
case missingDbPath(path: String)
|
case missingDbPath(path: String)
|
||||||
case dataDbInitFailed(path: String)
|
case dataDbInitFailed(path: String)
|
||||||
case connectionError(message: String)
|
case connectionError(underlyingError: Error)
|
||||||
case grpcError(statusCode: Int, message: String)
|
case grpcError(statusCode: Int, message: String)
|
||||||
|
case connectionTimeout
|
||||||
case generalError(message: String)
|
case generalError(message: String)
|
||||||
case maxAttemptsReached(attempts: Int)
|
case maxAttemptsReached(attempts: Int)
|
||||||
|
case unspecifiedError(underlyingError: Error)
|
||||||
|
case criticalError
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
CompactBlockProcessor notification userInfo object keys.
|
CompactBlockProcessor notification userInfo object keys.
|
||||||
|
@ -686,16 +689,9 @@ public class CompactBlockProcessor {
|
||||||
NotificationCenter.default.post(name: Notification.Name.blockProcessorFailed, object: self, userInfo: [CompactBlockProcessorNotificationKey.error: mapError(err)])
|
NotificationCenter.default.post(name: Notification.Name.blockProcessorFailed, object: self, userInfo: [CompactBlockProcessorNotificationKey.error: mapError(err)])
|
||||||
}
|
}
|
||||||
// TODO: encapsulate service errors better
|
// TODO: encapsulate service errors better
|
||||||
func mapError(_ error: Error) -> Error {
|
func mapError(_ error: Error) -> CompactBlockProcessorError {
|
||||||
if let lwdError = error as? LightWalletServiceError {
|
if let lwdError = error as? LightWalletServiceError {
|
||||||
switch lwdError {
|
return lwdError.mapToProcessorError()
|
||||||
case .failed(let statusCode, let message):
|
|
||||||
return CompactBlockProcessorError.connectionError(message: "Connection failed - Status code: \(statusCode) - message: \(message)")
|
|
||||||
case .invalidBlock:
|
|
||||||
return CompactBlockProcessorError.generalError(message: "Invalid block: \(lwdError)")
|
|
||||||
default:
|
|
||||||
return CompactBlockProcessorError.generalError(message: "Error: \(lwdError)")
|
|
||||||
}
|
|
||||||
} else if let rpcError = error as? GRPC.GRPCStatus {
|
} else if let rpcError = error as? GRPC.GRPCStatus {
|
||||||
switch rpcError {
|
switch rpcError {
|
||||||
case .ok:
|
case .ok:
|
||||||
|
@ -707,7 +703,7 @@ public class CompactBlockProcessor {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return error
|
return .unspecifiedError(underlyingError: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -721,6 +717,30 @@ public extension CompactBlockProcessor.Configuration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension LightWalletServiceError {
|
||||||
|
func mapToProcessorError() -> CompactBlockProcessorError {
|
||||||
|
switch self {
|
||||||
|
case .failed(let statusCode, let message):
|
||||||
|
return CompactBlockProcessorError.grpcError(statusCode: statusCode, message: message)
|
||||||
|
case .invalidBlock:
|
||||||
|
return CompactBlockProcessorError.generalError(message: "\(self)")
|
||||||
|
case .generalError(let message):
|
||||||
|
return CompactBlockProcessorError.generalError(message: message)
|
||||||
|
case .sentFailed(let error):
|
||||||
|
return CompactBlockProcessorError.connectionError(underlyingError: error)
|
||||||
|
case .genericError(let error):
|
||||||
|
return CompactBlockProcessorError.unspecifiedError(underlyingError: error)
|
||||||
|
case .timeOut:
|
||||||
|
return CompactBlockProcessorError.connectionTimeout
|
||||||
|
case .criticalError:
|
||||||
|
return CompactBlockProcessorError.criticalError
|
||||||
|
case .userCancelled:
|
||||||
|
return CompactBlockProcessorError.connectionTimeout
|
||||||
|
case .unknown:
|
||||||
|
return CompactBlockProcessorError.unspecifiedError(underlyingError: self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
extension CompactBlockProcessor.State: Equatable {
|
extension CompactBlockProcessor.State: Equatable {
|
||||||
public static func == (lhs: CompactBlockProcessor.State, rhs: CompactBlockProcessor.State) -> Bool {
|
public static func == (lhs: CompactBlockProcessor.State, rhs: CompactBlockProcessor.State) -> Bool {
|
||||||
switch lhs {
|
switch lhs {
|
||||||
|
|
|
@ -9,8 +9,24 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import GRPC
|
import GRPC
|
||||||
import NIO
|
import NIO
|
||||||
|
import NIOHPACK
|
||||||
public typealias Channel = GRPC.GRPCChannel
|
public typealias Channel = GRPC.GRPCChannel
|
||||||
|
|
||||||
|
|
||||||
|
extension TimeAmount {
|
||||||
|
static let singleCallTimeout = TimeAmount.seconds(10)
|
||||||
|
static let streamingCallTimeout = TimeAmount.seconds(90)
|
||||||
|
}
|
||||||
|
extension CallOptions {
|
||||||
|
static var lwdCall: CallOptions {
|
||||||
|
CallOptions(customMetadata: HPACKHeaders(),
|
||||||
|
timeLimit: .timeout(.singleCallTimeout),
|
||||||
|
messageEncoding: .disabled,
|
||||||
|
requestIDProvider: .autogenerated,
|
||||||
|
requestIDHeader: nil,
|
||||||
|
cacheable: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
Swift GRPC implementation of Lightwalletd service */
|
Swift GRPC implementation of Lightwalletd service */
|
||||||
public class LightWalletGRPCService {
|
public class LightWalletGRPCService {
|
||||||
|
@ -22,7 +38,7 @@ public class LightWalletGRPCService {
|
||||||
|
|
||||||
public init(channel: Channel) {
|
public init(channel: Channel) {
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
compactTxStreamer = CompactTxStreamerClient(channel: self.channel)
|
compactTxStreamer = CompactTxStreamerClient(channel: self.channel, defaultCallOptions: CallOptions.lwdCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
public convenience init(endpoint: LightWalletEndpoint) {
|
public convenience init(endpoint: LightWalletEndpoint) {
|
||||||
|
@ -59,9 +75,14 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
public func fetchTransaction(txId: Data) throws -> TransactionEntity {
|
public func fetchTransaction(txId: Data) throws -> TransactionEntity {
|
||||||
var txFilter = TxFilter()
|
var txFilter = TxFilter()
|
||||||
txFilter.hash = txId
|
txFilter.hash = txId
|
||||||
|
|
||||||
|
do {
|
||||||
let rawTx = try compactTxStreamer.getTransaction(txFilter).response.wait()
|
let rawTx = try compactTxStreamer.getTransaction(txFilter).response.wait()
|
||||||
|
|
||||||
return TransactionBuilder.createTransactionEntity(txId: txId, rawTransaction: rawTx)
|
return TransactionBuilder.createTransactionEntity(txId: txId, rawTransaction: rawTx)
|
||||||
|
} catch {
|
||||||
|
throw error.mapToServiceError()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
|
public func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
|
||||||
|
@ -73,7 +94,7 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
|
|
||||||
switch response {
|
switch response {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
result(.failure(LightWalletServiceError.genericError(error: error)))
|
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)))
|
||||||
}
|
}
|
||||||
|
@ -88,13 +109,13 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
response.whenComplete { (responseResult) in
|
response.whenComplete { (responseResult) in
|
||||||
switch responseResult {
|
switch responseResult {
|
||||||
case .failure(let e):
|
case .failure(let e):
|
||||||
result(.failure(LightWalletServiceError.genericError(error: e)))
|
result(.failure(LightWalletServiceError.sentFailed(error: e)))
|
||||||
case .success(let s):
|
case .success(let s):
|
||||||
result(.success(s))
|
result(.success(s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
result(.failure(LightWalletServiceError.genericError(error: error)))
|
result(.failure(error.mapToServiceError()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +124,11 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
let rawTx = RawTransaction.with { (raw) in
|
let rawTx = RawTransaction.with { (raw) in
|
||||||
raw.data = spendTransaction
|
raw.data = spendTransaction
|
||||||
}
|
}
|
||||||
|
do {
|
||||||
return try compactTxStreamer.sendTransaction(rawTx).response.wait()
|
return try compactTxStreamer.sendTransaction(rawTx).response.wait()
|
||||||
|
} catch {
|
||||||
|
throw error.mapToServiceError()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func blockRange(_ range: CompactBlockRange) throws -> [ZcashCompactBlock] {
|
public func blockRange(_ range: CompactBlockRange) throws -> [ZcashCompactBlock] {
|
||||||
|
@ -113,18 +138,21 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
blocks.append($0)
|
blocks.append($0)
|
||||||
})
|
})
|
||||||
|
|
||||||
do {
|
let status = try response.status.wait()
|
||||||
_ = try response.status.wait()
|
switch status.code {
|
||||||
} catch {
|
|
||||||
throw LightWalletServiceError.genericError(error: error)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
case .ok:
|
||||||
do {
|
do {
|
||||||
return try blocks.asZcashCompactBlocks()
|
return try blocks.asZcashCompactBlocks()
|
||||||
} catch {
|
} catch {
|
||||||
LoggerProxy.error("invalid block in range: \(range) - Error: \(error)")
|
LoggerProxy.error("invalid block in range: \(range) - Error: \(error)")
|
||||||
throw LightWalletServiceError.genericError(error: error)
|
throw LightWalletServiceError.genericError(error: error)
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
throw LightWalletServiceError.mapCode(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void) {
|
public func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void) {
|
||||||
|
@ -132,19 +160,18 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
|
|
||||||
response.whenSuccess { (blockID) in
|
response.whenSuccess { (blockID) in
|
||||||
guard let blockHeight = Int(exactly: blockID.height) else {
|
guard let blockHeight = Int(exactly: blockID.height) else {
|
||||||
result(.failure(LightWalletServiceError.generalError))
|
result(.failure(LightWalletServiceError.generalError(message: "error creating blockheight from BlockID \(blockID)")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
result(.success(blockHeight))
|
result(.success(blockHeight))
|
||||||
}
|
}
|
||||||
|
|
||||||
response.whenFailure { (error) in
|
response.whenFailure { (error) in
|
||||||
result(.failure(LightWalletServiceError.genericError(error: error)))
|
result(.failure(error.mapToServiceError()))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make cancellable
|
|
||||||
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
|
||||||
|
@ -162,15 +189,16 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
do {
|
do {
|
||||||
result(.success(try blocks.asZcashCompactBlocks()))
|
result(.success(try blocks.asZcashCompactBlocks()))
|
||||||
} catch {
|
} catch {
|
||||||
result(.failure(LightWalletServiceError.generalError))
|
LoggerProxy.error("Error parsing compact blocks \(error)")
|
||||||
|
result(.failure(LightWalletServiceError.invalidBlock))
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
result(Result.failure(LightWalletServiceError.failed(statusCode: status.code.rawValue, message: status.message ?? "No Message")))
|
result(.failure(.mapCode(status)))
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
result(.failure(LightWalletServiceError.genericError(error: error)))
|
result(.failure(error.mapToServiceError()))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -184,5 +212,34 @@ extension LightWalletGRPCService: LightWalletService {
|
||||||
}
|
}
|
||||||
return height
|
return height
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Error {
|
||||||
|
func mapToServiceError() -> LightWalletServiceError {
|
||||||
|
guard let grpcError = self as? GRPCStatusTransformable
|
||||||
|
else {
|
||||||
|
return LightWalletServiceError.genericError(error: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
return LightWalletServiceError.mapCode(grpcError.makeGRPCStatus())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension LightWalletServiceError {
|
||||||
|
static func mapCode(_ status: GRPCStatus) -> LightWalletServiceError {
|
||||||
|
switch status.code {
|
||||||
|
|
||||||
|
case .ok:
|
||||||
|
return LightWalletServiceError.unknown
|
||||||
|
case .cancelled:
|
||||||
|
return LightWalletServiceError.userCancelled
|
||||||
|
case .unknown:
|
||||||
|
return LightWalletServiceError.unknown
|
||||||
|
|
||||||
|
case .deadlineExceeded:
|
||||||
|
return LightWalletServiceError.timeOut
|
||||||
|
default:
|
||||||
|
return LightWalletServiceError.genericError(error: status)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,20 +14,24 @@ import SwiftProtobuf
|
||||||
Wrapper for errors received from a Lightwalletd endpoint
|
Wrapper for errors received from a Lightwalletd endpoint
|
||||||
*/
|
*/
|
||||||
public enum LightWalletServiceError: Error {
|
public enum LightWalletServiceError: Error {
|
||||||
case generalError
|
case generalError(message: String)
|
||||||
case failed(statusCode: Int, message: String)
|
case failed(statusCode: Int, message: String)
|
||||||
case invalidBlock
|
case invalidBlock
|
||||||
case sentFailed(sendResponse: LightWalletServiceResponse)
|
case sentFailed(error: Error)
|
||||||
case genericError(error: Error)
|
case genericError(error: Error)
|
||||||
|
case timeOut
|
||||||
|
case criticalError
|
||||||
|
case userCancelled
|
||||||
|
case unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
extension LightWalletServiceError: Equatable {
|
extension LightWalletServiceError: Equatable {
|
||||||
public static func == (lhs: Self, rhs: Self) -> Bool {
|
public static func == (lhs: Self, rhs: Self) -> Bool {
|
||||||
switch lhs {
|
switch lhs {
|
||||||
case .generalError:
|
case .generalError(let m):
|
||||||
switch rhs {
|
switch rhs {
|
||||||
case .generalError:
|
case .generalError(let msg):
|
||||||
return true
|
return m == msg
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -46,18 +50,46 @@ extension LightWalletServiceError: Equatable {
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case .sentFailed(let sendResponse):
|
case .sentFailed(_):
|
||||||
switch rhs {
|
switch rhs {
|
||||||
case .sentFailed(let response):
|
case .sentFailed(_):
|
||||||
return response.errorCode == sendResponse.errorCode
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case .genericError:
|
case .genericError:
|
||||||
return false
|
return false
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
case .timeOut:
|
||||||
|
switch rhs {
|
||||||
|
case .timeOut:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case .criticalError:
|
||||||
|
switch rhs {
|
||||||
|
case .criticalError:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case .userCancelled:
|
||||||
|
switch rhs {
|
||||||
|
case .userCancelled:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case .unknown:
|
||||||
|
switch rhs {
|
||||||
|
case .unknown:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public protocol LightWalletServiceResponse {
|
public protocol LightWalletServiceResponse {
|
||||||
|
|
|
@ -14,10 +14,13 @@ Represents errors thrown by a Synchronizer
|
||||||
public enum SynchronizerError: Error {
|
public enum SynchronizerError: Error {
|
||||||
case initFailed(message: String)
|
case initFailed(message: String)
|
||||||
case syncFailed
|
case syncFailed
|
||||||
case connectionFailed(message: String)
|
case connectionFailed(message: Error)
|
||||||
case generalError(message: String)
|
case generalError(message: String)
|
||||||
case maxRetryAttemptsReached(attempts: Int)
|
case maxRetryAttemptsReached(attempts: Int)
|
||||||
case connectionError(status: Int, message: String)
|
case connectionError(status: Int, message: String)
|
||||||
|
case networkTimeout
|
||||||
|
case uncategorized(underlyingError: Error)
|
||||||
|
case criticalError
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -142,15 +142,18 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
try processor.start(retry: retry)
|
try processor.start(retry: retry)
|
||||||
|
} catch {
|
||||||
|
throw mapError(error)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Stops the synchronizer
|
Stops the synchronizer
|
||||||
- Throws: CompactBlockProcessorError when failures occur
|
|
||||||
*/
|
*/
|
||||||
public func stop() throws {
|
public func stop() {
|
||||||
|
|
||||||
defer {
|
defer {
|
||||||
|
|
||||||
|
@ -329,6 +332,8 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
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)
|
||||||
|
} else {
|
||||||
|
self.notifyFailure(CompactBlockProcessorError.generalError(message: "This is strange. processorFailed Call received no error message"))
|
||||||
}
|
}
|
||||||
self.status = .disconnected
|
self.status = .disconnected
|
||||||
}
|
}
|
||||||
|
@ -400,9 +405,7 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func applicationWillTerminate(_ notification: Notification) {
|
@objc func applicationWillTerminate(_ notification: Notification) {
|
||||||
do {
|
stop()
|
||||||
try stop()
|
|
||||||
} catch {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Synchronizer methods
|
// MARK: Synchronizer methods
|
||||||
|
@ -547,9 +550,15 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
return SynchronizerError.maxRetryAttemptsReached(attempts: attempts)
|
return SynchronizerError.maxRetryAttemptsReached(attempts: attempts)
|
||||||
case .grpcError(let statusCode, let message):
|
case .grpcError(let statusCode, let message):
|
||||||
return SynchronizerError.connectionError(status: statusCode, message: message)
|
return SynchronizerError.connectionError(status: statusCode, message: message)
|
||||||
|
case .connectionTimeout:
|
||||||
|
return SynchronizerError.networkTimeout
|
||||||
|
case .unspecifiedError(let underlyingError):
|
||||||
|
return SynchronizerError.uncategorized(underlyingError: underlyingError)
|
||||||
|
case .criticalError:
|
||||||
|
return SynchronizerError.criticalError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return error
|
return SynchronizerError.uncategorized(underlyingError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func notifyFailure(_ error: Error) {
|
private func notifyFailure(_ error: Error) {
|
||||||
|
|
|
@ -79,14 +79,14 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func processorFailed(_ notification: Notification) {
|
@objc func processorFailed(_ notification: Notification) {
|
||||||
DispatchQueue.main.sync {
|
|
||||||
XCTAssertNotNil(notification.userInfo)
|
XCTAssertNotNil(notification.userInfo)
|
||||||
if let error = notification.userInfo?["error"] {
|
if let error = notification.userInfo?["error"] {
|
||||||
XCTFail("CompactBlockProcessor failed with Error: \(error)")
|
XCTFail("CompactBlockProcessor failed with Error: \(error)")
|
||||||
} else {
|
} else {
|
||||||
XCTFail("CompactBlockProcessor failed")
|
XCTFail("CompactBlockProcessor failed")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func startProcessing() {
|
fileprivate func startProcessing() {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import os
|
import os
|
||||||
import ZcashLightClientKit
|
import ZcashLightClientKit
|
||||||
class SampleLogger: Logger {
|
class SampleLogger: ZcashLightClientKit.Logger {
|
||||||
enum LogLevel: Int {
|
enum LogLevel: Int {
|
||||||
case debug
|
case debug
|
||||||
case error
|
case error
|
||||||
|
|
|
@ -13,7 +13,7 @@ import SwiftProtobuf
|
||||||
|
|
||||||
class AwfulLightWalletService: MockLightWalletService {
|
class AwfulLightWalletService: MockLightWalletService {
|
||||||
override func latestBlockHeight() throws -> BlockHeight {
|
override func latestBlockHeight() throws -> BlockHeight {
|
||||||
throw LightWalletServiceError.generalError
|
throw LightWalletServiceError.criticalError
|
||||||
}
|
}
|
||||||
|
|
||||||
override func blockRange(_ range: CompactBlockRange) throws -> [ZcashCompactBlock] {
|
override func blockRange(_ range: CompactBlockRange) throws -> [ZcashCompactBlock] {
|
||||||
|
@ -22,20 +22,20 @@ class AwfulLightWalletService: MockLightWalletService {
|
||||||
|
|
||||||
override func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void) {
|
override func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void) {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||||
result(.failure(LightWalletServiceError.generalError))
|
result(.failure(LightWalletServiceError.invalidBlock))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void) {
|
override func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void) {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||||
result(.failure(LightWalletServiceError.generalError))
|
result(.failure(LightWalletServiceError.invalidBlock))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse,LightWalletServiceError>) -> Void) {
|
override func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse,LightWalletServiceError>) -> Void) {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||||
result(.failure(LightWalletServiceError.generalError))
|
result(.failure(LightWalletServiceError.invalidBlock))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ class AwfulLightWalletService: MockLightWalletService {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
override func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
|
override func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
|
||||||
throw LightWalletServiceError.generalError
|
throw LightWalletServiceError.invalidBlock
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue