Feature/reorg testing (#104)
* Add DarksideWalletD class * darkside walletd reorg tests * Removed hardcoded stuff from tests * add parameters to support other kinds of reorgs * Basic reorg test in place * Integration to DarksideWalletD and tests * tests improvements * Implement reorg testing. fix error throwing
This commit is contained in:
parent
51419010ea
commit
312a169911
|
@ -30,10 +30,10 @@ PODS:
|
|||
- gRPC-Core (~> 1.23.0)
|
||||
- SwiftProtobuf (~> 1.7.0)
|
||||
- SwiftProtobuf (1.7.0)
|
||||
- ZcashLightClientKit (0.2.1):
|
||||
- ZcashLightClientKit (0.3.1):
|
||||
- SQLite.swift (~> 0.12.2)
|
||||
- SwiftGRPC (~> 0.10.0)
|
||||
- ZcashLightClientKit/Tests (0.2.1):
|
||||
- ZcashLightClientKit/Tests (0.3.1):
|
||||
- SQLite.swift (~> 0.12.2)
|
||||
- SwiftGRPC (~> 0.10.0)
|
||||
|
||||
|
@ -72,7 +72,7 @@ SPEC CHECKSUMS:
|
|||
SQLite.swift: d2b4642190917051ce6bd1d49aab565fe794eea3
|
||||
SwiftGRPC: f8fcfecb547c96cc6913de619f95fa3cd09838ee
|
||||
SwiftProtobuf: 4fd9645e69b72cbae6ec8da5be0cdd20ca6565dd
|
||||
ZcashLightClientKit: 8f195725d2ec3d579c78b228a0d3a384e21f56b9
|
||||
ZcashLightClientKit: 24b01a37977bddfaadc7746acef40ad209bae84a
|
||||
|
||||
PODFILE CHECKSUM: 5a1fb98512fa179a4e83d67d14dd402f6d129a4d
|
||||
|
||||
|
|
|
@ -204,7 +204,7 @@ public class CompactBlockProcessor {
|
|||
}
|
||||
var shouldStart: Bool {
|
||||
switch self.state {
|
||||
case .stopped, .synced, .error(_):
|
||||
case .stopped, .synced, .error:
|
||||
return maxAttemptsReached
|
||||
default:
|
||||
return false
|
||||
|
@ -276,7 +276,6 @@ public class CompactBlockProcessor {
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Stops the CompactBlockProcessor
|
||||
|
||||
|
@ -408,7 +407,6 @@ public class CompactBlockProcessor {
|
|||
self?.state = .scanning
|
||||
}
|
||||
|
||||
|
||||
scanBlocksOperation.completionHandler = { [weak self] (finished, cancelled) in
|
||||
guard !cancelled else {
|
||||
LoggerProxy.debug("Warning: scanBlocksOperation operation cancelled")
|
||||
|
@ -571,7 +569,7 @@ public class CompactBlockProcessor {
|
|||
self.retryAttempts = self.retryAttempts + 1
|
||||
self.processingError = error
|
||||
switch self.state {
|
||||
case .error(_):
|
||||
case .error:
|
||||
notifyError(error)
|
||||
default:
|
||||
break
|
||||
|
|
|
@ -15,6 +15,8 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
|||
zcashlc_clear_last_error()
|
||||
if message.contains("couldn't load Sapling spend parameters") {
|
||||
return RustWeldingError.saplingSpendParametersNotFound
|
||||
} else if message.contains("is not empty") {
|
||||
return RustWeldingError.dataDbNotEmpty
|
||||
}
|
||||
return RustWeldingError.genericError(message: message)
|
||||
}
|
||||
|
@ -83,7 +85,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
|||
let dbData = dbData.osStr()
|
||||
guard zcashlc_init_blocks_table(dbData.0, dbData.1, height, [CChar](hash.utf8CString), time, [CChar](saplingTree.utf8CString)) != 0 else {
|
||||
if let error = lastError() {
|
||||
throw throwDataDbError(error)
|
||||
throw error
|
||||
}
|
||||
throw RustWeldingError.dataDbInitFailed(message: "Unknown Error")
|
||||
}
|
||||
|
|
|
@ -21,11 +21,11 @@ public struct ZcashRustBackendWeldingConstants {
|
|||
|
||||
public protocol ZcashRustBackendWelding {
|
||||
/**
|
||||
gets the latest error if available
|
||||
gets the latest error if available. Clear the existing error
|
||||
*/
|
||||
static func lastError() -> RustWeldingError?
|
||||
/**
|
||||
gets the latest error message from librustzcash
|
||||
gets the latest error message from librustzcash. Does not clear existing error
|
||||
*/
|
||||
static func getLastError() -> String?
|
||||
/**
|
||||
|
|
|
@ -3,16 +3,20 @@
|
|||
// Generated by the Swift generator plugin for the protocol buffer compiler.
|
||||
// Source: compact_formats.proto
|
||||
//
|
||||
// For information on using the generated types, please see the documentation:
|
||||
// For information on using the generated types, please see the documenation:
|
||||
// https://github.com/apple/swift-protobuf/
|
||||
|
||||
// Copyright (c) 2019-2020 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
import Foundation
|
||||
import SwiftProtobuf
|
||||
|
||||
// If the compiler emits an error on this type, it is because this file
|
||||
// was generated by a version of the `protoc` Swift plug-in that is
|
||||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// Please ensure that your are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
|
@ -51,14 +55,14 @@ struct CompactBlock {
|
|||
init() {}
|
||||
}
|
||||
|
||||
/// Index and hash will allow the receiver to call out to chain
|
||||
/// explorers or other data structures to retrieve more information
|
||||
/// about this transaction.
|
||||
struct CompactTx {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
/// Index and hash will allow the receiver to call out to chain
|
||||
/// explorers or other data structures to retrieve more information
|
||||
/// about this transaction.
|
||||
var index: UInt64 = 0
|
||||
|
||||
var hash: Data = SwiftProtobuf.Internal.emptyData
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright (c) 2019-2020 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
syntax = "proto3";
|
||||
package cash.z.wallet.sdk.rpc;
|
||||
option go_package = "walletrpc";
|
||||
|
@ -19,10 +23,10 @@ message CompactBlock {
|
|||
repeated CompactTx vtx = 7; // compact transactions from this block
|
||||
}
|
||||
|
||||
message CompactTx {
|
||||
// Index and hash will allow the receiver to call out to chain
|
||||
// explorers or other data structures to retrieve more information
|
||||
// about this transaction.
|
||||
message CompactTx {
|
||||
uint64 index = 1;
|
||||
bytes hash = 2;
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright (c) 2019-2020 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
syntax = "proto3";
|
||||
package cash.z.wallet.sdk.rpc;
|
||||
option go_package = "walletrpc";
|
||||
|
@ -5,15 +9,14 @@ option swift_prefix = "";
|
|||
import "compact_formats.proto";
|
||||
|
||||
// A BlockID message contains identifiers to select a block: a height or a
|
||||
// hash. If the hash is present it takes precedence.
|
||||
// hash. Specification by hash is not implemented, but may be in the future.
|
||||
message BlockID {
|
||||
uint64 height = 1;
|
||||
bytes hash = 2;
|
||||
}
|
||||
|
||||
// BlockRange technically allows ranging from hash to hash etc but this is not
|
||||
// currently intended for support, though there is no reason you couldn't do
|
||||
// it. Further permutations are left as an exercise.
|
||||
// BlockRange specifies a series of blocks from start to end inclusive.
|
||||
// Both BlockIDs must be heights; specification by hash is not yet supported.
|
||||
message BlockRange {
|
||||
BlockID start = 1;
|
||||
BlockID end = 2;
|
||||
|
@ -21,29 +24,81 @@ message BlockRange {
|
|||
|
||||
// A TxFilter contains the information needed to identify a particular
|
||||
// transaction: either a block and an index, or a direct transaction hash.
|
||||
// Currently, only specification by hash is supported.
|
||||
message TxFilter {
|
||||
BlockID block = 1;
|
||||
uint64 index = 2;
|
||||
bytes hash = 3;
|
||||
}
|
||||
|
||||
// RawTransaction contains the complete transaction data.
|
||||
// RawTransaction contains the complete transaction data. It also optionally includes
|
||||
// the block height in which the transaction was included
|
||||
message RawTransaction {
|
||||
bytes data = 1;
|
||||
uint64 height = 2;
|
||||
}
|
||||
|
||||
// A SendResponse encodes an error code and a string. It is currently used
|
||||
// only by SendTransaction(). If error code is zero, the operation was
|
||||
// successful; if non-zero, it and the message specify the failure.
|
||||
message SendResponse {
|
||||
int32 errorCode = 1;
|
||||
string errorMessage = 2;
|
||||
}
|
||||
|
||||
// Empty placeholder. Someday we may want to specify e.g. a particular chain fork.
|
||||
// Chainspec is a placeholder to allow specification of a particular chain fork.
|
||||
message ChainSpec {}
|
||||
|
||||
// Empty is for gRPCs that take no arguments, currently only GetLightdInfo.
|
||||
message Empty {}
|
||||
|
||||
// LightdInfo returns various information about this lightwalletd instance
|
||||
// and the state of the blockchain.
|
||||
message LightdInfo {
|
||||
string version = 1;
|
||||
string vendor = 2;
|
||||
bool taddrSupport = 3;
|
||||
string chainName = 4;
|
||||
uint64 saplingActivationHeight = 5;
|
||||
string consensusBranchId = 6;
|
||||
uint64 blockHeight = 7;
|
||||
}
|
||||
|
||||
// TransparentAddressBlockFilter restricts the results to the given address
|
||||
// or block range.
|
||||
message TransparentAddressBlockFilter {
|
||||
string address = 1;
|
||||
BlockRange range = 2;
|
||||
}
|
||||
|
||||
// Duration is currently used only for testing, so that the Ping rpc
|
||||
// can simulate a delay, to create many simultaneous connections. Units
|
||||
// are microseconds.
|
||||
message Duration {
|
||||
int64 intervalUs = 1;
|
||||
}
|
||||
|
||||
// PingResponse is used to indicate concurrency, how many Ping rpcs
|
||||
// are executing upon entry and upon exit (after the delay).
|
||||
message PingResponse {
|
||||
int64 entry = 1;
|
||||
int64 exit = 2;
|
||||
}
|
||||
|
||||
service CompactTxStreamer {
|
||||
// Compact Blocks
|
||||
rpc GetLatestBlock(ChainSpec) returns (BlockID) {}
|
||||
rpc GetBlock(BlockID) returns (CompactBlock) {}
|
||||
rpc GetBlockRange(BlockRange) returns (stream CompactBlock) {}
|
||||
|
||||
// Transactions
|
||||
rpc GetTransaction(TxFilter) returns (RawTransaction) {}
|
||||
rpc SendTransaction(RawTransaction) returns (SendResponse) {}
|
||||
|
||||
// t-Address support
|
||||
rpc GetAddressTxids(TransparentAddressBlockFilter) returns (stream RawTransaction) {}
|
||||
|
||||
// Misc
|
||||
rpc GetLightdInfo(Empty) returns (LightdInfo) {}
|
||||
rpc Ping(Duration) returns (PingResponse) {}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,34 @@ fileprivate final class CompactTxStreamerSendTransactionCallBase: ClientCallUnar
|
|||
override class var method: String { return "/cash.z.wallet.sdk.rpc.CompactTxStreamer/SendTransaction" }
|
||||
}
|
||||
|
||||
internal protocol CompactTxStreamerGetAddressTxidsCall: ClientCallServerStreaming {
|
||||
/// Do not call this directly, call `receive()` in the protocol extension below instead.
|
||||
func _receive(timeout: DispatchTime) throws -> RawTransaction?
|
||||
/// Call this to wait for a result. Nonblocking.
|
||||
func receive(completion: @escaping (ResultOrRPCError<RawTransaction?>) -> Void) throws
|
||||
}
|
||||
|
||||
internal extension CompactTxStreamerGetAddressTxidsCall {
|
||||
/// Call this to wait for a result. Blocking.
|
||||
func receive(timeout: DispatchTime = .distantFuture) throws -> RawTransaction? { return try self._receive(timeout: timeout) }
|
||||
}
|
||||
|
||||
fileprivate final class CompactTxStreamerGetAddressTxidsCallBase: ClientCallServerStreamingBase<TransparentAddressBlockFilter, RawTransaction>, CompactTxStreamerGetAddressTxidsCall {
|
||||
override class var method: String { return "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetAddressTxids" }
|
||||
}
|
||||
|
||||
internal protocol CompactTxStreamerGetLightdInfoCall: ClientCallUnary {}
|
||||
|
||||
fileprivate final class CompactTxStreamerGetLightdInfoCallBase: ClientCallUnaryBase<Empty, LightdInfo>, CompactTxStreamerGetLightdInfoCall {
|
||||
override class var method: String { return "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetLightdInfo" }
|
||||
}
|
||||
|
||||
internal protocol CompactTxStreamerPingCall: ClientCallUnary {}
|
||||
|
||||
fileprivate final class CompactTxStreamerPingCallBase: ClientCallUnaryBase<Duration, PingResponse>, CompactTxStreamerPingCall {
|
||||
override class var method: String { return "/cash.z.wallet.sdk.rpc.CompactTxStreamer/Ping" }
|
||||
}
|
||||
|
||||
|
||||
/// Instantiate CompactTxStreamerServiceClient, then call methods of this protocol to make API calls.
|
||||
internal protocol CompactTxStreamerService: ServiceClient {
|
||||
|
@ -97,6 +125,23 @@ internal protocol CompactTxStreamerService: ServiceClient {
|
|||
@discardableResult
|
||||
func sendTransaction(_ request: RawTransaction, metadata customMetadata: Metadata, completion: @escaping (SendResponse?, CallResult) -> Void) throws -> CompactTxStreamerSendTransactionCall
|
||||
|
||||
/// Asynchronous. Server-streaming.
|
||||
/// Send the initial message.
|
||||
/// Use methods on the returned object to get streamed responses.
|
||||
func getAddressTxids(_ request: TransparentAddressBlockFilter, metadata customMetadata: Metadata, completion: ((CallResult) -> Void)?) throws -> CompactTxStreamerGetAddressTxidsCall
|
||||
|
||||
/// Synchronous. Unary.
|
||||
func getLightdInfo(_ request: Empty, metadata customMetadata: Metadata) throws -> LightdInfo
|
||||
/// Asynchronous. Unary.
|
||||
@discardableResult
|
||||
func getLightdInfo(_ request: Empty, metadata customMetadata: Metadata, completion: @escaping (LightdInfo?, CallResult) -> Void) throws -> CompactTxStreamerGetLightdInfoCall
|
||||
|
||||
/// Synchronous. Unary.
|
||||
func ping(_ request: Duration, metadata customMetadata: Metadata) throws -> PingResponse
|
||||
/// Asynchronous. Unary.
|
||||
@discardableResult
|
||||
func ping(_ request: Duration, metadata customMetadata: Metadata, completion: @escaping (PingResponse?, CallResult) -> Void) throws -> CompactTxStreamerPingCall
|
||||
|
||||
}
|
||||
|
||||
internal extension CompactTxStreamerService {
|
||||
|
@ -145,6 +190,31 @@ internal extension CompactTxStreamerService {
|
|||
return try self.sendTransaction(request, metadata: self.metadata, completion: completion)
|
||||
}
|
||||
|
||||
/// Asynchronous. Server-streaming.
|
||||
func getAddressTxids(_ request: TransparentAddressBlockFilter, completion: ((CallResult) -> Void)?) throws -> CompactTxStreamerGetAddressTxidsCall {
|
||||
return try self.getAddressTxids(request, metadata: self.metadata, completion: completion)
|
||||
}
|
||||
|
||||
/// Synchronous. Unary.
|
||||
func getLightdInfo(_ request: Empty) throws -> LightdInfo {
|
||||
return try self.getLightdInfo(request, metadata: self.metadata)
|
||||
}
|
||||
/// Asynchronous. Unary.
|
||||
@discardableResult
|
||||
func getLightdInfo(_ request: Empty, completion: @escaping (LightdInfo?, CallResult) -> Void) throws -> CompactTxStreamerGetLightdInfoCall {
|
||||
return try self.getLightdInfo(request, metadata: self.metadata, completion: completion)
|
||||
}
|
||||
|
||||
/// Synchronous. Unary.
|
||||
func ping(_ request: Duration) throws -> PingResponse {
|
||||
return try self.ping(request, metadata: self.metadata)
|
||||
}
|
||||
/// Asynchronous. Unary.
|
||||
@discardableResult
|
||||
func ping(_ request: Duration, completion: @escaping (PingResponse?, CallResult) -> Void) throws -> CompactTxStreamerPingCall {
|
||||
return try self.ping(request, metadata: self.metadata, completion: completion)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal final class CompactTxStreamerServiceClient: ServiceClientBase, CompactTxStreamerService {
|
||||
|
@ -204,5 +274,37 @@ internal final class CompactTxStreamerServiceClient: ServiceClientBase, CompactT
|
|||
.start(request: request, metadata: customMetadata, completion: completion)
|
||||
}
|
||||
|
||||
/// Asynchronous. Server-streaming.
|
||||
/// Send the initial message.
|
||||
/// Use methods on the returned object to get streamed responses.
|
||||
internal func getAddressTxids(_ request: TransparentAddressBlockFilter, metadata customMetadata: Metadata, completion: ((CallResult) -> Void)?) throws -> CompactTxStreamerGetAddressTxidsCall {
|
||||
return try CompactTxStreamerGetAddressTxidsCallBase(channel)
|
||||
.start(request: request, metadata: customMetadata, completion: completion)
|
||||
}
|
||||
|
||||
/// Synchronous. Unary.
|
||||
internal func getLightdInfo(_ request: Empty, metadata customMetadata: Metadata) throws -> LightdInfo {
|
||||
return try CompactTxStreamerGetLightdInfoCallBase(channel)
|
||||
.run(request: request, metadata: customMetadata)
|
||||
}
|
||||
/// Asynchronous. Unary.
|
||||
@discardableResult
|
||||
internal func getLightdInfo(_ request: Empty, metadata customMetadata: Metadata, completion: @escaping (LightdInfo?, CallResult) -> Void) throws -> CompactTxStreamerGetLightdInfoCall {
|
||||
return try CompactTxStreamerGetLightdInfoCallBase(channel)
|
||||
.start(request: request, metadata: customMetadata, completion: completion)
|
||||
}
|
||||
|
||||
/// Synchronous. Unary.
|
||||
internal func ping(_ request: Duration, metadata customMetadata: Metadata) throws -> PingResponse {
|
||||
return try CompactTxStreamerPingCallBase(channel)
|
||||
.run(request: request, metadata: customMetadata)
|
||||
}
|
||||
/// Asynchronous. Unary.
|
||||
@discardableResult
|
||||
internal func ping(_ request: Duration, metadata customMetadata: Metadata, completion: @escaping (PingResponse?, CallResult) -> Void) throws -> CompactTxStreamerPingCall {
|
||||
return try CompactTxStreamerPingCallBase(channel)
|
||||
.start(request: request, metadata: customMetadata, completion: completion)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -3,16 +3,20 @@
|
|||
// Generated by the Swift generator plugin for the protocol buffer compiler.
|
||||
// Source: service.proto
|
||||
//
|
||||
// For information on using the generated types, please see the documentation:
|
||||
// For information on using the generated types, please see the documenation:
|
||||
// https://github.com/apple/swift-protobuf/
|
||||
|
||||
// Copyright (c) 2019-2020 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
import Foundation
|
||||
import SwiftProtobuf
|
||||
|
||||
// If the compiler emits an error on this type, it is because this file
|
||||
// was generated by a version of the `protoc` Swift plug-in that is
|
||||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// Please ensure that your are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
|
@ -20,7 +24,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
|
|||
}
|
||||
|
||||
/// A BlockID message contains identifiers to select a block: a height or a
|
||||
/// hash. If the hash is present it takes precedence.
|
||||
/// hash. Specification by hash is not implemented, but may be in the future.
|
||||
struct BlockID {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
|
@ -35,68 +39,74 @@ struct BlockID {
|
|||
init() {}
|
||||
}
|
||||
|
||||
/// BlockRange technically allows ranging from hash to hash etc but this is not
|
||||
/// currently intended for support, though there is no reason you couldn't do
|
||||
/// it. Further permutations are left as an exercise.
|
||||
/// BlockRange specifies a series of blocks from start to end inclusive.
|
||||
/// Both BlockIDs must be heights; specification by hash is not yet supported.
|
||||
struct BlockRange {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var start: BlockID {
|
||||
get {return _start ?? BlockID()}
|
||||
set {_start = newValue}
|
||||
get {return _storage._start ?? BlockID()}
|
||||
set {_uniqueStorage()._start = newValue}
|
||||
}
|
||||
/// Returns true if `start` has been explicitly set.
|
||||
var hasStart: Bool {return self._start != nil}
|
||||
var hasStart: Bool {return _storage._start != nil}
|
||||
/// Clears the value of `start`. Subsequent reads from it will return its default value.
|
||||
mutating func clearStart() {self._start = nil}
|
||||
mutating func clearStart() {_uniqueStorage()._start = nil}
|
||||
|
||||
var end: BlockID {
|
||||
get {return _end ?? BlockID()}
|
||||
set {_end = newValue}
|
||||
get {return _storage._end ?? BlockID()}
|
||||
set {_uniqueStorage()._end = newValue}
|
||||
}
|
||||
/// Returns true if `end` has been explicitly set.
|
||||
var hasEnd: Bool {return self._end != nil}
|
||||
var hasEnd: Bool {return _storage._end != nil}
|
||||
/// Clears the value of `end`. Subsequent reads from it will return its default value.
|
||||
mutating func clearEnd() {self._end = nil}
|
||||
mutating func clearEnd() {_uniqueStorage()._end = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
|
||||
fileprivate var _start: BlockID? = nil
|
||||
fileprivate var _end: BlockID? = nil
|
||||
fileprivate var _storage = _StorageClass.defaultInstance
|
||||
}
|
||||
|
||||
/// A TxFilter contains the information needed to identify a particular
|
||||
/// transaction: either a block and an index, or a direct transaction hash.
|
||||
/// Currently, only specification by hash is supported.
|
||||
struct TxFilter {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var block: BlockID {
|
||||
get {return _block ?? BlockID()}
|
||||
set {_block = newValue}
|
||||
get {return _storage._block ?? BlockID()}
|
||||
set {_uniqueStorage()._block = newValue}
|
||||
}
|
||||
/// Returns true if `block` has been explicitly set.
|
||||
var hasBlock: Bool {return self._block != nil}
|
||||
var hasBlock: Bool {return _storage._block != nil}
|
||||
/// Clears the value of `block`. Subsequent reads from it will return its default value.
|
||||
mutating func clearBlock() {self._block = nil}
|
||||
mutating func clearBlock() {_uniqueStorage()._block = nil}
|
||||
|
||||
var index: UInt64 = 0
|
||||
var index: UInt64 {
|
||||
get {return _storage._index}
|
||||
set {_uniqueStorage()._index = newValue}
|
||||
}
|
||||
|
||||
var hash: Data = SwiftProtobuf.Internal.emptyData
|
||||
var hash: Data {
|
||||
get {return _storage._hash}
|
||||
set {_uniqueStorage()._hash = newValue}
|
||||
}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
|
||||
fileprivate var _block: BlockID? = nil
|
||||
fileprivate var _storage = _StorageClass.defaultInstance
|
||||
}
|
||||
|
||||
/// RawTransaction contains the complete transaction data.
|
||||
/// RawTransaction contains the complete transaction data. It also optionally includes
|
||||
/// the block height in which the transaction was included
|
||||
struct RawTransaction {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
|
@ -104,11 +114,16 @@ struct RawTransaction {
|
|||
|
||||
var data: Data = SwiftProtobuf.Internal.emptyData
|
||||
|
||||
var height: UInt64 = 0
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
/// A SendResponse encodes an error code and a string. It is currently used
|
||||
/// only by SendTransaction(). If error code is zero, the operation was
|
||||
/// successful; if non-zero, it and the message specify the failure.
|
||||
struct SendResponse {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
|
@ -123,7 +138,7 @@ struct SendResponse {
|
|||
init() {}
|
||||
}
|
||||
|
||||
/// Empty placeholder. Someday we may want to specify e.g. a particular chain fork.
|
||||
/// Chainspec is a placeholder to allow specification of a particular chain fork.
|
||||
struct ChainSpec {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
|
@ -134,6 +149,102 @@ struct ChainSpec {
|
|||
init() {}
|
||||
}
|
||||
|
||||
/// Empty is for gRPCs that take no arguments, currently only GetLightdInfo.
|
||||
struct Empty {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
/// LightdInfo returns various information about this lightwalletd instance
|
||||
/// and the state of the blockchain.
|
||||
struct LightdInfo {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var version: String = String()
|
||||
|
||||
var vendor: String = String()
|
||||
|
||||
var taddrSupport: Bool = false
|
||||
|
||||
var chainName: String = String()
|
||||
|
||||
var saplingActivationHeight: UInt64 = 0
|
||||
|
||||
var consensusBranchID: String = String()
|
||||
|
||||
var blockHeight: UInt64 = 0
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
/// TransparentAddressBlockFilter restricts the results to the given address
|
||||
/// or block range.
|
||||
struct TransparentAddressBlockFilter {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var address: String {
|
||||
get {return _storage._address}
|
||||
set {_uniqueStorage()._address = newValue}
|
||||
}
|
||||
|
||||
var range: BlockRange {
|
||||
get {return _storage._range ?? BlockRange()}
|
||||
set {_uniqueStorage()._range = newValue}
|
||||
}
|
||||
/// Returns true if `range` has been explicitly set.
|
||||
var hasRange: Bool {return _storage._range != nil}
|
||||
/// Clears the value of `range`. Subsequent reads from it will return its default value.
|
||||
mutating func clearRange() {_uniqueStorage()._range = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
|
||||
fileprivate var _storage = _StorageClass.defaultInstance
|
||||
}
|
||||
|
||||
/// Duration is currently used only for testing, so that the Ping rpc
|
||||
/// can simulate a delay, to create many simultaneous connections. Units
|
||||
/// are microseconds.
|
||||
struct Duration {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var intervalUs: Int64 = 0
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
/// PingResponse is used to indicate concurrency, how many Ping rpcs
|
||||
/// are executing upon entry and upon exit (after the delay).
|
||||
struct PingResponse {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var entry: Int64 = 0
|
||||
|
||||
var exit: Int64 = 0
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "cash.z.wallet.sdk.rpc"
|
||||
|
@ -180,29 +291,63 @@ extension BlockRange: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
|
|||
2: .same(proto: "end"),
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
var _start: BlockID? = nil
|
||||
var _end: BlockID? = nil
|
||||
|
||||
static let defaultInstance = _StorageClass()
|
||||
|
||||
private init() {}
|
||||
|
||||
init(copying source: _StorageClass) {
|
||||
_start = source._start
|
||||
_end = source._end
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate mutating func _uniqueStorage() -> _StorageClass {
|
||||
if !isKnownUniquelyReferenced(&_storage) {
|
||||
_storage = _StorageClass(copying: _storage)
|
||||
}
|
||||
return _storage
|
||||
}
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
_ = _uniqueStorage()
|
||||
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularMessageField(value: &self._start)
|
||||
case 2: try decoder.decodeSingularMessageField(value: &self._end)
|
||||
case 1: try decoder.decodeSingularMessageField(value: &_storage._start)
|
||||
case 2: try decoder.decodeSingularMessageField(value: &_storage._end)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if let v = self._start {
|
||||
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
if let v = _storage._start {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
|
||||
}
|
||||
if let v = self._end {
|
||||
if let v = _storage._end {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
|
||||
}
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: BlockRange, rhs: BlockRange) -> Bool {
|
||||
if lhs._start != rhs._start {return false}
|
||||
if lhs._end != rhs._end {return false}
|
||||
if lhs._storage !== rhs._storage {
|
||||
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
|
||||
let _storage = _args.0
|
||||
let rhs_storage = _args.1
|
||||
if _storage._start != rhs_storage._start {return false}
|
||||
if _storage._end != rhs_storage._end {return false}
|
||||
return true
|
||||
}
|
||||
if !storagesAreEqual {return false}
|
||||
}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
|
@ -216,34 +361,70 @@ extension TxFilter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
|||
3: .same(proto: "hash"),
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
var _block: BlockID? = nil
|
||||
var _index: UInt64 = 0
|
||||
var _hash: Data = SwiftProtobuf.Internal.emptyData
|
||||
|
||||
static let defaultInstance = _StorageClass()
|
||||
|
||||
private init() {}
|
||||
|
||||
init(copying source: _StorageClass) {
|
||||
_block = source._block
|
||||
_index = source._index
|
||||
_hash = source._hash
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate mutating func _uniqueStorage() -> _StorageClass {
|
||||
if !isKnownUniquelyReferenced(&_storage) {
|
||||
_storage = _StorageClass(copying: _storage)
|
||||
}
|
||||
return _storage
|
||||
}
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
_ = _uniqueStorage()
|
||||
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularMessageField(value: &self._block)
|
||||
case 2: try decoder.decodeSingularUInt64Field(value: &self.index)
|
||||
case 3: try decoder.decodeSingularBytesField(value: &self.hash)
|
||||
case 1: try decoder.decodeSingularMessageField(value: &_storage._block)
|
||||
case 2: try decoder.decodeSingularUInt64Field(value: &_storage._index)
|
||||
case 3: try decoder.decodeSingularBytesField(value: &_storage._hash)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if let v = self._block {
|
||||
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
if let v = _storage._block {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
|
||||
}
|
||||
if self.index != 0 {
|
||||
try visitor.visitSingularUInt64Field(value: self.index, fieldNumber: 2)
|
||||
if _storage._index != 0 {
|
||||
try visitor.visitSingularUInt64Field(value: _storage._index, fieldNumber: 2)
|
||||
}
|
||||
if !_storage._hash.isEmpty {
|
||||
try visitor.visitSingularBytesField(value: _storage._hash, fieldNumber: 3)
|
||||
}
|
||||
if !self.hash.isEmpty {
|
||||
try visitor.visitSingularBytesField(value: self.hash, fieldNumber: 3)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: TxFilter, rhs: TxFilter) -> Bool {
|
||||
if lhs._block != rhs._block {return false}
|
||||
if lhs.index != rhs.index {return false}
|
||||
if lhs.hash != rhs.hash {return false}
|
||||
if lhs._storage !== rhs._storage {
|
||||
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
|
||||
let _storage = _args.0
|
||||
let rhs_storage = _args.1
|
||||
if _storage._block != rhs_storage._block {return false}
|
||||
if _storage._index != rhs_storage._index {return false}
|
||||
if _storage._hash != rhs_storage._hash {return false}
|
||||
return true
|
||||
}
|
||||
if !storagesAreEqual {return false}
|
||||
}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
|
@ -253,12 +434,14 @@ extension RawTransaction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement
|
|||
static let protoMessageName: String = _protobuf_package + ".RawTransaction"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "data"),
|
||||
2: .same(proto: "height"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularBytesField(value: &self.data)
|
||||
case 2: try decoder.decodeSingularUInt64Field(value: &self.height)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -268,11 +451,15 @@ extension RawTransaction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement
|
|||
if !self.data.isEmpty {
|
||||
try visitor.visitSingularBytesField(value: self.data, fieldNumber: 1)
|
||||
}
|
||||
if self.height != 0 {
|
||||
try visitor.visitSingularUInt64Field(value: self.height, fieldNumber: 2)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: RawTransaction, rhs: RawTransaction) -> Bool {
|
||||
if lhs.data != rhs.data {return false}
|
||||
if lhs.height != rhs.height {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
|
@ -331,3 +518,220 @@ extension ChainSpec: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
|
|||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension Empty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".Empty"
|
||||
static let _protobuf_nameMap = SwiftProtobuf._NameMap()
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let _ = try decoder.nextFieldNumber() {
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: Empty, rhs: Empty) -> Bool {
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension LightdInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".LightdInfo"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "version"),
|
||||
2: .same(proto: "vendor"),
|
||||
3: .same(proto: "taddrSupport"),
|
||||
4: .same(proto: "chainName"),
|
||||
5: .same(proto: "saplingActivationHeight"),
|
||||
6: .same(proto: "consensusBranchId"),
|
||||
7: .same(proto: "blockHeight"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularStringField(value: &self.version)
|
||||
case 2: try decoder.decodeSingularStringField(value: &self.vendor)
|
||||
case 3: try decoder.decodeSingularBoolField(value: &self.taddrSupport)
|
||||
case 4: try decoder.decodeSingularStringField(value: &self.chainName)
|
||||
case 5: try decoder.decodeSingularUInt64Field(value: &self.saplingActivationHeight)
|
||||
case 6: try decoder.decodeSingularStringField(value: &self.consensusBranchID)
|
||||
case 7: try decoder.decodeSingularUInt64Field(value: &self.blockHeight)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if !self.version.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.version, fieldNumber: 1)
|
||||
}
|
||||
if !self.vendor.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.vendor, fieldNumber: 2)
|
||||
}
|
||||
if self.taddrSupport != false {
|
||||
try visitor.visitSingularBoolField(value: self.taddrSupport, fieldNumber: 3)
|
||||
}
|
||||
if !self.chainName.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.chainName, fieldNumber: 4)
|
||||
}
|
||||
if self.saplingActivationHeight != 0 {
|
||||
try visitor.visitSingularUInt64Field(value: self.saplingActivationHeight, fieldNumber: 5)
|
||||
}
|
||||
if !self.consensusBranchID.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.consensusBranchID, fieldNumber: 6)
|
||||
}
|
||||
if self.blockHeight != 0 {
|
||||
try visitor.visitSingularUInt64Field(value: self.blockHeight, fieldNumber: 7)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: LightdInfo, rhs: LightdInfo) -> Bool {
|
||||
if lhs.version != rhs.version {return false}
|
||||
if lhs.vendor != rhs.vendor {return false}
|
||||
if lhs.taddrSupport != rhs.taddrSupport {return false}
|
||||
if lhs.chainName != rhs.chainName {return false}
|
||||
if lhs.saplingActivationHeight != rhs.saplingActivationHeight {return false}
|
||||
if lhs.consensusBranchID != rhs.consensusBranchID {return false}
|
||||
if lhs.blockHeight != rhs.blockHeight {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension TransparentAddressBlockFilter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".TransparentAddressBlockFilter"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "address"),
|
||||
2: .same(proto: "range"),
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
var _address: String = String()
|
||||
var _range: BlockRange? = nil
|
||||
|
||||
static let defaultInstance = _StorageClass()
|
||||
|
||||
private init() {}
|
||||
|
||||
init(copying source: _StorageClass) {
|
||||
_address = source._address
|
||||
_range = source._range
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate mutating func _uniqueStorage() -> _StorageClass {
|
||||
if !isKnownUniquelyReferenced(&_storage) {
|
||||
_storage = _StorageClass(copying: _storage)
|
||||
}
|
||||
return _storage
|
||||
}
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
_ = _uniqueStorage()
|
||||
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularStringField(value: &_storage._address)
|
||||
case 2: try decoder.decodeSingularMessageField(value: &_storage._range)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
if !_storage._address.isEmpty {
|
||||
try visitor.visitSingularStringField(value: _storage._address, fieldNumber: 1)
|
||||
}
|
||||
if let v = _storage._range {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
|
||||
}
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: TransparentAddressBlockFilter, rhs: TransparentAddressBlockFilter) -> Bool {
|
||||
if lhs._storage !== rhs._storage {
|
||||
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
|
||||
let _storage = _args.0
|
||||
let rhs_storage = _args.1
|
||||
if _storage._address != rhs_storage._address {return false}
|
||||
if _storage._range != rhs_storage._range {return false}
|
||||
return true
|
||||
}
|
||||
if !storagesAreEqual {return false}
|
||||
}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension Duration: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".Duration"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "intervalUs"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularInt64Field(value: &self.intervalUs)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if self.intervalUs != 0 {
|
||||
try visitor.visitSingularInt64Field(value: self.intervalUs, fieldNumber: 1)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: Duration, rhs: Duration) -> Bool {
|
||||
if lhs.intervalUs != rhs.intervalUs {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension PingResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".PingResponse"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "entry"),
|
||||
2: .same(proto: "exit"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularInt64Field(value: &self.entry)
|
||||
case 2: try decoder.decodeSingularInt64Field(value: &self.exit)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if self.entry != 0 {
|
||||
try visitor.visitSingularInt64Field(value: self.entry, fieldNumber: 1)
|
||||
}
|
||||
if self.exit != 0 {
|
||||
try visitor.visitSingularInt64Field(value: self.exit, fieldNumber: 2)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: PingResponse, rhs: PingResponse) -> Bool {
|
||||
if lhs.entry != rhs.entry {return false}
|
||||
if lhs.exit != rhs.exit {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,13 +26,20 @@ public extension WalletBirthday {
|
|||
time: 1574579149,
|
||||
tree: "01999fc372390699b15f71d41745abe6a2ea0db4ffa8894d3c5fe30b9261a1a43a01585112668685bd6783cb01b72d17dc86c6d740c27cccf66b75e959e4e4f5ea3710019b7f6b4457a97eadbe1a39bfcc6ba0a56d37010d0d799e1e652fc29733103e04016a0b4d2705e1feb2021d80e5785608536dde05aea5ef676a5427244228b19e2d00010973d03ad5f79fcac64ab3ffbdaaac1a24b74a3617770bf960fb004cbd422439000001984bfce9361025cc38574f944a3ed7b074b3bf88cfce6f14c4a9be4d91d6dc730105871ec1e3737a39bceb00b0c2d253ff36f472e92c361e7ef360d49ea8dc4c4200000001c145105e1bf401668a8f23ca70c47ee92d23bd366072020c83d26b855eeafd6d0001fa6980c053d84f809b6abcf35690f03a11f87b28e3240828e32e3f57af41e54e01319312241b0031e3a255b0d708750b4cb3f3fe79e3503fe488cc8db1dd00753801754bb593ea42d231a7ddf367640f09bbf59dc00f2c1d2003cc340e0c016b5b13"
|
||||
)
|
||||
case 663000 ..< 663700:
|
||||
case 663000 ..< 663150:
|
||||
return WalletBirthday(
|
||||
height: 663000,
|
||||
hash: "0000000000bd422264b700bb33cab167ab42392c89db0e7c8ce30d57f346fe69",
|
||||
time: 1576810013,
|
||||
tree: "0102f02a8cd23e35502f8efa55893c7a145168ac3fa00d4bd032b55097bbe0335a01b57c362e3c834f2216c72ae0d8a335fd2397cc80073d0f5b29c419028bc6c94c100000000157bfd70afa37c8bf0c60c9e160d2145bdfbcf07837b0ff90bf8a5108722cc85400000000011bc9521263584de20822f9483e7edb5af54150c4823c775b2efc6a1eded9625501a6030f8d4b588681eddb66cad63f09c5c7519db49500fc56ebd481ce5e903c22000163f4eec5a2fe00a5f45e71e1542ff01e937d2210c99f03addcce5314a5278b2d0163ab01f46a3bb6ea46f5a19d5bdd59eb3f81e19cfa6d10ab0fd5566c7a16992601fa6980c053d84f809b6abcf35690f03a11f87b28e3240828e32e3f57af41e54e01319312241b0031e3a255b0d708750b4cb3f3fe79e3503fe488cc8db1dd00753801754bb593ea42d231a7ddf367640f09bbf59dc00f2c1d2003cc340e0c016b5b13"
|
||||
)
|
||||
case 663150 ..< 663700:
|
||||
return WalletBirthday(
|
||||
height: 663150,
|
||||
hash: "0000000002fd3be4c24c437bd22620901617125ec2a3a6c902ec9a6c06f734fc",
|
||||
time: 1576821833,
|
||||
tree: "01ec6278a1bed9e1b080fd60ef50eb17411645e3746ff129283712bc4757ecc833001001b4e1d4a26ac4a2810b57a14f4ffb69395f55dde5674ecd2462af96f9126e054701a36afb68534f640938bdffd80dfcb3f4d5e232488abbf67d049b33a761e7ed6901a16e35205fb7fe626a9b13fc43e1d2b98a9c241f99f93d5e93a735454073025401f5b9bcbf3d0e3c83f95ee79299e8aeadf30af07717bda15ffb7a3d00243b58570001fa6d4c2390e205f81d86b85ace0b48f3ce0afb78eeef3e14c70bcfd7c5f0191c0000011bc9521263584de20822f9483e7edb5af54150c4823c775b2efc6a1eded9625501a6030f8d4b588681eddb66cad63f09c5c7519db49500fc56ebd481ce5e903c22000163f4eec5a2fe00a5f45e71e1542ff01e937d2210c99f03addcce5314a5278b2d0163ab01f46a3bb6ea46f5a19d5bdd59eb3f81e19cfa6d10ab0fd5566c7a16992601fa6980c053d84f809b6abcf35690f03a11f87b28e3240828e32e3f57af41e54e01319312241b0031e3a255b0d708750b4cb3f3fe79e3503fe488cc8db1dd00753801754bb593ea42d231a7ddf367640f09bbf59dc00f2c1d2003cc340e0c016b5b13"
|
||||
)
|
||||
case 663700 ..< 670000:
|
||||
return WalletBirthday(
|
||||
height: 663700,
|
||||
|
|
|
@ -64,7 +64,6 @@ public extension Notification.Name {
|
|||
*/
|
||||
public class SDKSynchronizer: Synchronizer {
|
||||
|
||||
|
||||
public struct NotificationKeys {
|
||||
public static let progress = "SDKSynchronizer.progress"
|
||||
public static let blockHeight = "SDKSynchronizer.blockHeight"
|
||||
|
|
|
@ -86,7 +86,7 @@ class BlockDownloaderTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testFailure() {
|
||||
let awfulDownloader = CompactBlockDownloader(service: AwfulLightWalletService(latestBlockHeight: 281_000), storage: ZcashConsoleFakeStorage())
|
||||
let awfulDownloader = CompactBlockDownloader(service: AwfulLightWalletService(latestBlockHeight: ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 1000), storage: ZcashConsoleFakeStorage())
|
||||
|
||||
let expect = XCTestExpectation(description: self.description)
|
||||
expect.expectedFulfillmentCount = 1
|
||||
|
|
|
@ -18,7 +18,7 @@ class CompactBlockProcessorTests: XCTestCase {
|
|||
var startedScanningNotificationExpectation: XCTestExpectation!
|
||||
var startedValidatingNotificationExpectation: XCTestExpectation!
|
||||
var idleNotificationExpectation: XCTestExpectation!
|
||||
let mockLatestHeight = 282_000
|
||||
let mockLatestHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 2000
|
||||
|
||||
override func setUp() {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
@ -108,27 +108,24 @@ class CompactBlockProcessorTests: XCTestCase {
|
|||
|
||||
// test first range
|
||||
var latestDownloadedHeight = processorConfig.walletBirthday // this can be either this or Wallet Birthday.
|
||||
var latestBlockchainHeight = BlockHeight(281_000)
|
||||
var latestBlockchainHeight = BlockHeight(ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 1000)
|
||||
|
||||
var expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight, upper:latestDownloadedHeight + processorConfig.downloadBatchSize - 1))
|
||||
|
||||
XCTAssertEqual(expectedBatchRange, processor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight))
|
||||
|
||||
// Test mid-range
|
||||
latestDownloadedHeight = BlockHeight(280_100)
|
||||
latestBlockchainHeight = BlockHeight(281_000)
|
||||
latestDownloadedHeight = BlockHeight(ZcashSDK.SAPLING_ACTIVATION_HEIGHT + ZcashSDK.DEFAULT_BATCH_SIZE)
|
||||
latestBlockchainHeight = BlockHeight(ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 1000)
|
||||
|
||||
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper:latestDownloadedHeight + processorConfig.downloadBatchSize))
|
||||
|
||||
XCTAssertEqual(expectedBatchRange, processor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight))
|
||||
|
||||
latestDownloadedHeight = BlockHeight(280_950)
|
||||
latestBlockchainHeight = BlockHeight(281_000)
|
||||
|
||||
// Test last batch range
|
||||
|
||||
latestDownloadedHeight = BlockHeight(280_950)
|
||||
latestBlockchainHeight = BlockHeight(281_000)
|
||||
latestDownloadedHeight = BlockHeight(ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 950)
|
||||
latestBlockchainHeight = BlockHeight(ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 1000)
|
||||
|
||||
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ class CompactBlockReorgTests: XCTestCase {
|
|||
var startedValidatingNotificationExpectation: XCTestExpectation!
|
||||
var idleNotificationExpectation: XCTestExpectation!
|
||||
var reorgNotificationExpectation: XCTestExpectation!
|
||||
let mockLatestHeight = 282_000
|
||||
let mockLatestHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 2000
|
||||
|
||||
override func setUp() {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
@ -33,7 +33,7 @@ class CompactBlockReorgTests: XCTestCase {
|
|||
let mockBackend = MockRustBackend.self
|
||||
mockBackend.mockValidateCombinedChainFailAfterAttempts = 3
|
||||
mockBackend.mockValidateCombinedChainKeepFailing = false
|
||||
mockBackend.mockValidateCombinedChainFailureHeight = 280_320
|
||||
mockBackend.mockValidateCombinedChainFailureHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 320
|
||||
|
||||
processor = CompactBlockProcessor(downloader: downloader,
|
||||
backend: mockBackend,
|
||||
|
@ -65,7 +65,7 @@ class CompactBlockReorgTests: XCTestCase {
|
|||
}
|
||||
|
||||
@objc func processorHandledReorg(_ notification: Notification) {
|
||||
// DispatchQueue.main.sync {
|
||||
|
||||
XCTAssertNotNil(notification.userInfo)
|
||||
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
|
||||
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
|
||||
|
@ -76,8 +76,6 @@ class CompactBlockReorgTests: XCTestCase {
|
|||
} else {
|
||||
XCTFail("CompactBlockProcessor reorg notification is malformed")
|
||||
}
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@objc func processorFailed(_ notification: Notification) {
|
||||
|
@ -88,7 +86,6 @@ class CompactBlockReorgTests: XCTestCase {
|
|||
} else {
|
||||
XCTFail("CompactBlockProcessor failed")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,10 +112,9 @@ class CompactBlockReorgTests: XCTestCase {
|
|||
downloadStartedExpect,
|
||||
startedValidatingNotificationExpectation,
|
||||
startedScanningNotificationExpectation,
|
||||
|
||||
reorgNotificationExpectation,
|
||||
idleNotificationExpectation,
|
||||
], timeout: 3000,enforceOrder: true)
|
||||
], timeout: 300,enforceOrder: true)
|
||||
}
|
||||
|
||||
private func expectedBatches(currentHeight: BlockHeight, targetHeight: BlockHeight, batchSize: Int) -> Int {
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
//
|
||||
// ReOrgTests.swift
|
||||
// ZcashLightClientKit-Unit-Tests
|
||||
//
|
||||
// Created by Francisco Gindre on 3/23/20.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import ZcashLightClientKit
|
||||
/**
|
||||
basic reorg test. Scan, get a reorg and then reach latest height.
|
||||
|
||||
* connect to dLWD
|
||||
* request latest height -> receive 663250
|
||||
* download and sync blocks from 663150 to 663250
|
||||
* trigger reorg by calling API (no need to pass params)**
|
||||
* request latest height -> receive 663251!
|
||||
* download that block
|
||||
* observe that the prev hash of that block does not match the hash that we have for 663250
|
||||
* rewind 10 blocks and request blocks 663241 to 663251
|
||||
*/
|
||||
class ReOrgTests: XCTestCase {
|
||||
|
||||
var processorConfig: CompactBlockProcessor.Configuration!
|
||||
var processor: CompactBlockProcessor!
|
||||
var darksideWalletService: DarksideWalletService!
|
||||
var downloader: CompactBlockDownloader!
|
||||
var downloadStartedExpect: XCTestExpectation!
|
||||
var updatedNotificationExpectation: XCTestExpectation!
|
||||
var stopNotificationExpectation: XCTestExpectation!
|
||||
var startedScanningNotificationExpectation: XCTestExpectation!
|
||||
var startedValidatingNotificationExpectation: XCTestExpectation!
|
||||
var idleNotificationExpectation: XCTestExpectation!
|
||||
var reorgNotificationExpectation: XCTestExpectation!
|
||||
var afterReorgIdleNotification: XCTestExpectation!
|
||||
var waitExpectation: XCTestExpectation!
|
||||
let mockLatestHeight = BlockHeight(663250)
|
||||
let targetLatestHeight = BlockHeight(663251)
|
||||
let walletBirthday = BlockHeight(663150)
|
||||
|
||||
override func setUpWithError() throws {
|
||||
logger = SampleLogger(logLevel: .debug)
|
||||
var config = CompactBlockProcessor.Configuration.standard
|
||||
|
||||
let birthday = WalletBirthday.birthday(with: walletBirthday)
|
||||
config.walletBirthday = birthday.height
|
||||
processorConfig = config
|
||||
|
||||
try? FileManager.default.removeItem(at: processorConfig.cacheDb)
|
||||
try? FileManager.default.removeItem(at: processorConfig.dataDb)
|
||||
let service = DarksideWalletService()
|
||||
darksideWalletService = service
|
||||
let storage = CompactBlockStorage.init(connectionProvider: SimpleConnectionProvider(path: processorConfig.cacheDb.absoluteString))
|
||||
try! storage.createTable()
|
||||
downloader = CompactBlockDownloader(service: service, storage: storage)
|
||||
processor = CompactBlockProcessor(downloader: downloader,
|
||||
backend: ZcashRustBackend.self,
|
||||
config: processorConfig)
|
||||
|
||||
downloadStartedExpect = XCTestExpectation(description: self.description + " downloadStartedExpect")
|
||||
stopNotificationExpectation = XCTestExpectation(description: self.description + " stopNotificationExpectation")
|
||||
updatedNotificationExpectation = XCTestExpectation(description: self.description + " updatedNotificationExpectation")
|
||||
startedValidatingNotificationExpectation = XCTestExpectation(description: self.description + " startedValidatingNotificationExpectation")
|
||||
startedScanningNotificationExpectation = XCTestExpectation(description: self.description + " startedScanningNotificationExpectation")
|
||||
idleNotificationExpectation = XCTestExpectation(description: self.description + " idleNotificationExpectation")
|
||||
afterReorgIdleNotification = XCTestExpectation(description: self.description + " afterReorgIdleNotification")
|
||||
reorgNotificationExpectation = XCTestExpectation(description: self.description + " reorgNotificationExpectation")
|
||||
|
||||
waitExpectation = XCTestExpectation(description: self.description + "waitExpectation")
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(processorHandledReorg(_:)), name: Notification.Name.blockProcessorHandledReOrg, object: processor)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(processorFailed(_:)), name: Notification.Name.blockProcessorFailed, object: processor)
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
try! FileManager.default.removeItem(at: processorConfig.cacheDb)
|
||||
try? FileManager.default.removeItem(at: processorConfig.dataDb)
|
||||
downloadStartedExpect.unsubscribeFromNotifications()
|
||||
stopNotificationExpectation.unsubscribeFromNotifications()
|
||||
updatedNotificationExpectation.unsubscribeFromNotifications()
|
||||
startedScanningNotificationExpectation.unsubscribeFromNotifications()
|
||||
startedValidatingNotificationExpectation.unsubscribeFromNotifications()
|
||||
idleNotificationExpectation.unsubscribeFromNotifications()
|
||||
reorgNotificationExpectation.unsubscribeFromNotifications()
|
||||
afterReorgIdleNotification.unsubscribeFromNotifications()
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
fileprivate func startProcessing() throws {
|
||||
XCTAssertNotNil(processor)
|
||||
|
||||
// Subscribe to notifications
|
||||
downloadStartedExpect.subscribe(to: Notification.Name.blockProcessorStartedDownloading, object: processor)
|
||||
stopNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStopped, object: processor)
|
||||
updatedNotificationExpectation.subscribe(to: Notification.Name.blockProcessorUpdated, object: processor)
|
||||
startedValidatingNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedValidating, object: processor)
|
||||
startedScanningNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedScanning, object: processor)
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(firstIdleNotification(_:)), name: Notification.Name.blockProcessorIdle, object: processor)
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleReOrgNotification(_:)), name: Notification.Name.blockProcessorHandledReOrg, object: processor)
|
||||
|
||||
try processor.start()
|
||||
}
|
||||
|
||||
@objc func firstIdleNotification(_ notification: Notification) {
|
||||
idleNotificationExpectation.fulfill()
|
||||
}
|
||||
|
||||
@objc func reOrgIdleNotification(_ notification: Notification) {
|
||||
afterReorgIdleNotification.fulfill()
|
||||
}
|
||||
|
||||
@objc func handleReOrgNotification(_ notification: Notification) {
|
||||
|
||||
reorgNotificationExpectation.fulfill()
|
||||
guard let reorgHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
|
||||
let rewindHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight else {
|
||||
XCTFail("malformed reorg userInfo")
|
||||
return
|
||||
}
|
||||
print("reorgHeight: \(reorgHeight)")
|
||||
print("rewindHeight: \(rewindHeight)")
|
||||
|
||||
XCTAssertTrue(reorgHeight > 0)
|
||||
XCTAssertNoThrow(rewindHeight > 0)
|
||||
}
|
||||
|
||||
func testBasicReOrg() throws {
|
||||
let mockLatestHeight = BlockHeight(663200)
|
||||
let targetLatestHeight = BlockHeight(663250)
|
||||
let reOrgHeight = BlockHeight(663195)
|
||||
let walletBirthday = WalletBirthday.birthday(with: 663151).height
|
||||
|
||||
try basicReOrgTest(firstLatestHeight: mockLatestHeight, reorgHeight: reOrgHeight, walletBirthday: walletBirthday, targetHeight: targetLatestHeight)
|
||||
}
|
||||
|
||||
func testTenPlusBlockReOrg() throws {
|
||||
let mockLatestHeight = BlockHeight(663200)
|
||||
let targetLatestHeight = BlockHeight(663250)
|
||||
let reOrgHeight = BlockHeight(663180)
|
||||
let walletBirthday = WalletBirthday.birthday(with: BlockHeight(663150)).height
|
||||
|
||||
try basicReOrgTest(firstLatestHeight: mockLatestHeight, reorgHeight: reOrgHeight, walletBirthday: walletBirthday, targetHeight: targetLatestHeight)
|
||||
}
|
||||
|
||||
func basicReOrgTest(firstLatestHeight: BlockHeight, reorgHeight: BlockHeight, walletBirthday: BlockHeight, targetHeight: BlockHeight) throws {
|
||||
|
||||
do {
|
||||
try darksideWalletService.setLatestHeight(firstLatestHeight)
|
||||
|
||||
} catch {
|
||||
XCTFail("Error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
connect to dLWD
|
||||
request latest height -> receive firstLatestHeight
|
||||
*/
|
||||
do {
|
||||
print("first latest height: \(try darksideWalletService.latestBlockHeight())")
|
||||
} catch {
|
||||
XCTFail("Error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
download and sync blocks from walletBirthday to firstLatestHeight
|
||||
*/
|
||||
do {
|
||||
try startProcessing()
|
||||
|
||||
} catch {
|
||||
XCTFail("Error: \(error)")
|
||||
}
|
||||
|
||||
wait(for: [downloadStartedExpect, startedValidatingNotificationExpectation,startedScanningNotificationExpectation, idleNotificationExpectation], timeout: 30)
|
||||
idleNotificationExpectation.unsubscribeFromNotifications()
|
||||
|
||||
/**
|
||||
verify that mock height has been reached
|
||||
*/
|
||||
var latestDownloadedHeight = BlockHeight(0)
|
||||
XCTAssertNoThrow(try {latestDownloadedHeight = try downloader.lastDownloadedBlockHeight()}())
|
||||
XCTAssertTrue(latestDownloadedHeight > 0)
|
||||
|
||||
/**
|
||||
trigger reorg!
|
||||
*/
|
||||
XCTAssertNoThrow(
|
||||
try darksideWalletService.triggerReOrg(latestHeight: targetHeight, reOrgHeight: reorgHeight)
|
||||
)
|
||||
|
||||
/**
|
||||
request latest height -> receive targetHeight!
|
||||
*/
|
||||
|
||||
XCTAssertNoThrow(try {latestDownloadedHeight = try downloader.lastDownloadedBlockHeight()}())
|
||||
afterReorgIdleNotification.subscribe(to: .blockProcessorIdle, object: processor)
|
||||
|
||||
/**
|
||||
request latest height -> receive targetHeight!
|
||||
download that block
|
||||
observe that the prev hash of that block does not match the hash that we have for firstLatestHeight
|
||||
rewind 10 blocks and request blocks targetHeight-10 to targetHeight
|
||||
*/
|
||||
try processor.start(retry: true)
|
||||
|
||||
// now reorg should happen and reorg notifications and idle notification should be triggered
|
||||
|
||||
wait(for: [reorgNotificationExpectation, afterReorgIdleNotification], timeout: 10)
|
||||
|
||||
// now everything should be fine. latest block should be targetHeight
|
||||
|
||||
XCTAssertNoThrow(try {latestDownloadedHeight = try downloader.lastDownloadedBlockHeight()}())
|
||||
XCTAssertEqual(latestDownloadedHeight, targetHeight)
|
||||
}
|
||||
|
||||
@objc func processorHandledReorg(_ notification: Notification) {
|
||||
|
||||
XCTAssertNotNil(notification.userInfo)
|
||||
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
|
||||
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
|
||||
|
||||
XCTAssertTrue( rewind <= mockLatestHeight - processorConfig.rewindDistance)
|
||||
XCTAssertTrue( rewind <= reorg )
|
||||
reorgNotificationExpectation.fulfill()
|
||||
} else {
|
||||
XCTFail("CompactBlockProcessor reorg notification is malformed")
|
||||
}
|
||||
}
|
||||
|
||||
@objc func processorFailed(_ notification: Notification) {
|
||||
XCTAssertNotNil(notification.userInfo)
|
||||
if let error = notification.userInfo?["error"] {
|
||||
XCTFail("CompactBlockProcessor failed with Error: \(error)")
|
||||
} else {
|
||||
XCTFail("CompactBlockProcessor failed")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
//
|
||||
// DO NOT EDIT.
|
||||
//
|
||||
// Generated by the protocol buffer compiler.
|
||||
// Source: darkside.proto
|
||||
//
|
||||
|
||||
//
|
||||
// Copyright 2018, gRPC Authors All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
import Dispatch
|
||||
import Foundation
|
||||
import SwiftGRPC
|
||||
import SwiftProtobuf
|
||||
@testable import ZcashLightClientKit
|
||||
internal protocol DarksideStreamerDarksideGetIncomingTransactionsCall: ClientCallServerStreaming {
|
||||
/// Do not call this directly, call `receive()` in the protocol extension below instead.
|
||||
func _receive(timeout: DispatchTime) throws -> RawTransaction?
|
||||
/// Call this to wait for a result. Nonblocking.
|
||||
func receive(completion: @escaping (ResultOrRPCError<RawTransaction?>) -> Void) throws
|
||||
}
|
||||
|
||||
internal extension DarksideStreamerDarksideGetIncomingTransactionsCall {
|
||||
/// Call this to wait for a result. Blocking.
|
||||
func receive(timeout: DispatchTime = .distantFuture) throws -> RawTransaction? { return try self._receive(timeout: timeout) }
|
||||
}
|
||||
|
||||
fileprivate final class DarksideStreamerDarksideGetIncomingTransactionsCallBase: ClientCallServerStreamingBase<Empty, RawTransaction>, DarksideStreamerDarksideGetIncomingTransactionsCall {
|
||||
override class var method: String { return "/cash.z.wallet.sdk.rpc.DarksideStreamer/DarksideGetIncomingTransactions" }
|
||||
}
|
||||
|
||||
internal protocol DarksideStreamerDarksideSetStateCall: ClientCallUnary {}
|
||||
|
||||
fileprivate final class DarksideStreamerDarksideSetStateCallBase: ClientCallUnaryBase<DarksideState, Empty>, DarksideStreamerDarksideSetStateCall {
|
||||
override class var method: String { return "/cash.z.wallet.sdk.rpc.DarksideStreamer/DarksideSetState" }
|
||||
}
|
||||
|
||||
|
||||
/// Instantiate DarksideStreamerServiceClient, then call methods of this protocol to make API calls.
|
||||
internal protocol DarksideStreamerService: ServiceClient {
|
||||
/// Asynchronous. Server-streaming.
|
||||
/// Send the initial message.
|
||||
/// Use methods on the returned object to get streamed responses.
|
||||
func darksideGetIncomingTransactions(_ request: Empty, metadata customMetadata: Metadata, completion: ((CallResult) -> Void)?) throws -> DarksideStreamerDarksideGetIncomingTransactionsCall
|
||||
|
||||
/// Synchronous. Unary.
|
||||
func darksideSetState(_ request: DarksideState, metadata customMetadata: Metadata) throws -> Empty
|
||||
/// Asynchronous. Unary.
|
||||
@discardableResult
|
||||
func darksideSetState(_ request: DarksideState, metadata customMetadata: Metadata, completion: @escaping (Empty?, CallResult) -> Void) throws -> DarksideStreamerDarksideSetStateCall
|
||||
|
||||
}
|
||||
|
||||
internal extension DarksideStreamerService {
|
||||
/// Asynchronous. Server-streaming.
|
||||
func darksideGetIncomingTransactions(_ request: Empty, completion: ((CallResult) -> Void)?) throws -> DarksideStreamerDarksideGetIncomingTransactionsCall {
|
||||
return try self.darksideGetIncomingTransactions(request, metadata: self.metadata, completion: completion)
|
||||
}
|
||||
|
||||
/// Synchronous. Unary.
|
||||
func darksideSetState(_ request: DarksideState) throws -> Empty {
|
||||
return try self.darksideSetState(request, metadata: self.metadata)
|
||||
}
|
||||
/// Asynchronous. Unary.
|
||||
@discardableResult
|
||||
func darksideSetState(_ request: DarksideState, completion: @escaping (Empty?, CallResult) -> Void) throws -> DarksideStreamerDarksideSetStateCall {
|
||||
return try self.darksideSetState(request, metadata: self.metadata, completion: completion)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal final class DarksideStreamerServiceClient: ServiceClientBase, DarksideStreamerService {
|
||||
/// Asynchronous. Server-streaming.
|
||||
/// Send the initial message.
|
||||
/// Use methods on the returned object to get streamed responses.
|
||||
internal func darksideGetIncomingTransactions(_ request: Empty, metadata customMetadata: Metadata, completion: ((CallResult) -> Void)?) throws -> DarksideStreamerDarksideGetIncomingTransactionsCall {
|
||||
return try DarksideStreamerDarksideGetIncomingTransactionsCallBase(channel)
|
||||
.start(request: request, metadata: customMetadata, completion: completion)
|
||||
}
|
||||
|
||||
/// Synchronous. Unary.
|
||||
internal func darksideSetState(_ request: DarksideState, metadata customMetadata: Metadata) throws -> Empty {
|
||||
return try DarksideStreamerDarksideSetStateCallBase(channel)
|
||||
.run(request: request, metadata: customMetadata)
|
||||
}
|
||||
/// Asynchronous. Unary.
|
||||
@discardableResult
|
||||
internal func darksideSetState(_ request: DarksideState, metadata customMetadata: Metadata, completion: @escaping (Empty?, CallResult) -> Void) throws -> DarksideStreamerDarksideSetStateCall {
|
||||
return try DarksideStreamerDarksideSetStateCallBase(channel)
|
||||
.start(request: request, metadata: customMetadata, completion: completion)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
// DO NOT EDIT.
|
||||
//
|
||||
// Generated by the Swift generator plugin for the protocol buffer compiler.
|
||||
// Source: darkside.proto
|
||||
//
|
||||
// For information on using the generated types, please see the documenation:
|
||||
// https://github.com/apple/swift-protobuf/
|
||||
|
||||
// Copyright (c) 2019-2020 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
import Foundation
|
||||
import SwiftProtobuf
|
||||
|
||||
// If the compiler emits an error on this type, it is because this file
|
||||
// was generated by a version of the `protoc` Swift plug-in that is
|
||||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that your are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
||||
struct DarksideState {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var latestHeight: UInt64 = 0
|
||||
|
||||
var reorgHeight: UInt64 = 0
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "cash.z.wallet.sdk.rpc"
|
||||
|
||||
extension DarksideState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".DarksideState"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "latestHeight"),
|
||||
2: .same(proto: "reorgHeight"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularUInt64Field(value: &self.latestHeight)
|
||||
case 2: try decoder.decodeSingularUInt64Field(value: &self.reorgHeight)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if self.latestHeight != 0 {
|
||||
try visitor.visitSingularUInt64Field(value: self.latestHeight, fieldNumber: 1)
|
||||
}
|
||||
if self.reorgHeight != 0 {
|
||||
try visitor.visitSingularUInt64Field(value: self.reorgHeight, fieldNumber: 2)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: DarksideState, rhs: DarksideState) -> Bool {
|
||||
if lhs.latestHeight != rhs.latestHeight {return false}
|
||||
if lhs.reorgHeight != rhs.reorgHeight {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) 2019-2020 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
syntax = "proto3";
|
||||
package cash.z.wallet.sdk.rpc;
|
||||
option go_package = "walletrpc";
|
||||
option swift_prefix = "";
|
||||
import "service.proto";
|
||||
|
||||
message DarksideState {
|
||||
uint64 latestHeight = 1;
|
||||
uint64 reorgHeight = 2;
|
||||
}
|
||||
|
||||
service DarksideStreamer {
|
||||
// Darkside (testing, see --darkside-very-insecure):
|
||||
|
||||
// Return the list of transactions that have been submitted (via SendTransaction).
|
||||
rpc DarksideGetIncomingTransactions(Empty) returns (stream RawTransaction) {}
|
||||
|
||||
// Set the information that GetLightdInfo returns, except that chainName specifies
|
||||
// a file of blocks within testdata/darkside that GetBlock will return.
|
||||
rpc DarksideSetState(DarksideState) returns (Empty) {}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// DarkSideWalletService.swift
|
||||
// ZcashLightClientKit-Unit-Tests
|
||||
//
|
||||
// Created by Francisco Gindre on 3/23/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ZcashLightClientKit
|
||||
import SwiftGRPC
|
||||
class DarksideWalletService: LightWalletService {
|
||||
var channel: Channel
|
||||
init() {
|
||||
let channel = ChannelProvider().channel()
|
||||
self.channel = channel
|
||||
self.service = LightWalletGRPCService(channel: channel)
|
||||
self.darksideService = DarksideStreamerServiceClient(channel: channel)
|
||||
}
|
||||
var service: LightWalletGRPCService
|
||||
var darksideService: DarksideStreamerServiceClient
|
||||
|
||||
func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void) {
|
||||
service.latestBlockHeight(result: result)
|
||||
}
|
||||
|
||||
func latestBlockHeight() throws -> BlockHeight {
|
||||
try service.latestBlockHeight()
|
||||
}
|
||||
|
||||
func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void) {
|
||||
service.blockRange(range, result: result)
|
||||
}
|
||||
|
||||
func blockRange(_ range: CompactBlockRange) throws -> [ZcashCompactBlock] {
|
||||
try service.blockRange(range)
|
||||
}
|
||||
|
||||
func submit(spendTransaction: Data, result: @escaping (Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
|
||||
service.submit(spendTransaction: spendTransaction, result: result)
|
||||
}
|
||||
|
||||
func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
|
||||
try service.submit(spendTransaction: spendTransaction)
|
||||
}
|
||||
|
||||
func triggerReOrg(latestHeight: BlockHeight, reOrgHeight: BlockHeight) throws {
|
||||
var darksideState = DarksideState()
|
||||
darksideState.latestHeight = UInt64(latestHeight)
|
||||
darksideState.reorgHeight = UInt64(reOrgHeight)
|
||||
|
||||
_ = try darksideService.darksideSetState(darksideState, metadata: Metadata())
|
||||
}
|
||||
|
||||
func setLatestHeight(_ latestHeight: BlockHeight) throws {
|
||||
var state = DarksideState()
|
||||
state.reorgHeight = 0
|
||||
state.latestHeight = UInt64(latestHeight)
|
||||
_ = try darksideService.darksideSetState(state, metadata: Metadata())
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// SampleLogger.swift
|
||||
// ZcashLightClientSample
|
||||
//
|
||||
// Created by Francisco Gindre on 3/9/20.
|
||||
// Copyright © 2020 Electric Coin Company. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import os
|
||||
import ZcashLightClientKit
|
||||
class SampleLogger: Logger {
|
||||
enum LogLevel: Int {
|
||||
case debug
|
||||
case error
|
||||
case warning
|
||||
case event
|
||||
case info
|
||||
}
|
||||
|
||||
var level: LogLevel
|
||||
init(logLevel: LogLevel) {
|
||||
self.level = logLevel
|
||||
}
|
||||
|
||||
private static let subsystem = Bundle.main.bundleIdentifier!
|
||||
static let oslog = OSLog(subsystem: subsystem, category: "test-logs")
|
||||
|
||||
func debug(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
|
||||
guard level.rawValue == LogLevel.debug.rawValue else { return }
|
||||
log(level: "DEBUG 🐞", message: message, file: file, function: function, line: line)
|
||||
}
|
||||
|
||||
func error(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
|
||||
guard level.rawValue <= LogLevel.error.rawValue else { return }
|
||||
log(level: "ERROR 💥", message: message, file: file, function: function, line: line)
|
||||
}
|
||||
|
||||
func warn(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
|
||||
guard level.rawValue <= LogLevel.warning.rawValue else { return }
|
||||
log(level: "WARNING ⚠️", message: message, file: file, function: function, line: line)
|
||||
}
|
||||
|
||||
func event(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
|
||||
guard level.rawValue <= LogLevel.event.rawValue else { return }
|
||||
log(level: "EVENT ⏱", message: message, file: file, function: function, line: line)
|
||||
}
|
||||
|
||||
func info(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
|
||||
guard level.rawValue <= LogLevel.info.rawValue else { return }
|
||||
log(level: "INFO ℹ️", message: message, file: file, function: function, line: line)
|
||||
}
|
||||
|
||||
private func log(level: String, message: String, file: String, function: String, line: Int) {
|
||||
let fileName = file as NSString
|
||||
|
||||
os_log("[%@] %@ - %@ - Line: %d -> %@", log: Self.oslog, type: .default, level, fileName.lastPathComponent, function, line, message)
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -219,4 +219,8 @@ class MockRustBackend: ZcashRustBackendWelding {
|
|||
nil
|
||||
}
|
||||
|
||||
static func decryptAndStoreTransaction(dbData: URL, tx: [UInt8]) -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ class LightWalletEndpointBuilder {
|
|||
}
|
||||
|
||||
class ChannelProvider {
|
||||
func channel() -> SwiftGRPC.Channel {
|
||||
Channel(address: Constants.address, secure: false)
|
||||
func channel(secure: Bool = false) -> SwiftGRPC.Channel {
|
||||
Channel(address: Constants.address, secure: secure)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue