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)
|
- gRPC-Core (~> 1.23.0)
|
||||||
- SwiftProtobuf (~> 1.7.0)
|
- SwiftProtobuf (~> 1.7.0)
|
||||||
- SwiftProtobuf (1.7.0)
|
- SwiftProtobuf (1.7.0)
|
||||||
- ZcashLightClientKit (0.2.1):
|
- ZcashLightClientKit (0.3.1):
|
||||||
- SQLite.swift (~> 0.12.2)
|
- SQLite.swift (~> 0.12.2)
|
||||||
- SwiftGRPC (~> 0.10.0)
|
- SwiftGRPC (~> 0.10.0)
|
||||||
- ZcashLightClientKit/Tests (0.2.1):
|
- ZcashLightClientKit/Tests (0.3.1):
|
||||||
- SQLite.swift (~> 0.12.2)
|
- SQLite.swift (~> 0.12.2)
|
||||||
- SwiftGRPC (~> 0.10.0)
|
- SwiftGRPC (~> 0.10.0)
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ SPEC CHECKSUMS:
|
||||||
SQLite.swift: d2b4642190917051ce6bd1d49aab565fe794eea3
|
SQLite.swift: d2b4642190917051ce6bd1d49aab565fe794eea3
|
||||||
SwiftGRPC: f8fcfecb547c96cc6913de619f95fa3cd09838ee
|
SwiftGRPC: f8fcfecb547c96cc6913de619f95fa3cd09838ee
|
||||||
SwiftProtobuf: 4fd9645e69b72cbae6ec8da5be0cdd20ca6565dd
|
SwiftProtobuf: 4fd9645e69b72cbae6ec8da5be0cdd20ca6565dd
|
||||||
ZcashLightClientKit: 8f195725d2ec3d579c78b228a0d3a384e21f56b9
|
ZcashLightClientKit: 24b01a37977bddfaadc7746acef40ad209bae84a
|
||||||
|
|
||||||
PODFILE CHECKSUM: 5a1fb98512fa179a4e83d67d14dd402f6d129a4d
|
PODFILE CHECKSUM: 5a1fb98512fa179a4e83d67d14dd402f6d129a4d
|
||||||
|
|
||||||
|
|
|
@ -204,7 +204,7 @@ public class CompactBlockProcessor {
|
||||||
}
|
}
|
||||||
var shouldStart: Bool {
|
var shouldStart: Bool {
|
||||||
switch self.state {
|
switch self.state {
|
||||||
case .stopped, .synced, .error(_):
|
case .stopped, .synced, .error:
|
||||||
return maxAttemptsReached
|
return maxAttemptsReached
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
@ -276,7 +276,6 @@ public class CompactBlockProcessor {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Stops the CompactBlockProcessor
|
Stops the CompactBlockProcessor
|
||||||
|
|
||||||
|
@ -408,7 +407,6 @@ public class CompactBlockProcessor {
|
||||||
self?.state = .scanning
|
self?.state = .scanning
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
scanBlocksOperation.completionHandler = { [weak self] (finished, cancelled) in
|
scanBlocksOperation.completionHandler = { [weak self] (finished, cancelled) in
|
||||||
guard !cancelled else {
|
guard !cancelled else {
|
||||||
LoggerProxy.debug("Warning: scanBlocksOperation operation cancelled")
|
LoggerProxy.debug("Warning: scanBlocksOperation operation cancelled")
|
||||||
|
@ -571,7 +569,7 @@ public class CompactBlockProcessor {
|
||||||
self.retryAttempts = self.retryAttempts + 1
|
self.retryAttempts = self.retryAttempts + 1
|
||||||
self.processingError = error
|
self.processingError = error
|
||||||
switch self.state {
|
switch self.state {
|
||||||
case .error(_):
|
case .error:
|
||||||
notifyError(error)
|
notifyError(error)
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
|
|
@ -15,6 +15,8 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
zcashlc_clear_last_error()
|
zcashlc_clear_last_error()
|
||||||
if message.contains("couldn't load Sapling spend parameters") {
|
if message.contains("couldn't load Sapling spend parameters") {
|
||||||
return RustWeldingError.saplingSpendParametersNotFound
|
return RustWeldingError.saplingSpendParametersNotFound
|
||||||
|
} else if message.contains("is not empty") {
|
||||||
|
return RustWeldingError.dataDbNotEmpty
|
||||||
}
|
}
|
||||||
return RustWeldingError.genericError(message: message)
|
return RustWeldingError.genericError(message: message)
|
||||||
}
|
}
|
||||||
|
@ -83,7 +85,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
let dbData = dbData.osStr()
|
let dbData = dbData.osStr()
|
||||||
guard zcashlc_init_blocks_table(dbData.0, dbData.1, height, [CChar](hash.utf8CString), time, [CChar](saplingTree.utf8CString)) != 0 else {
|
guard zcashlc_init_blocks_table(dbData.0, dbData.1, height, [CChar](hash.utf8CString), time, [CChar](saplingTree.utf8CString)) != 0 else {
|
||||||
if let error = lastError() {
|
if let error = lastError() {
|
||||||
throw throwDataDbError(error)
|
throw error
|
||||||
}
|
}
|
||||||
throw RustWeldingError.dataDbInitFailed(message: "Unknown Error")
|
throw RustWeldingError.dataDbInitFailed(message: "Unknown Error")
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,11 @@ public struct ZcashRustBackendWeldingConstants {
|
||||||
|
|
||||||
public protocol ZcashRustBackendWelding {
|
public protocol ZcashRustBackendWelding {
|
||||||
/**
|
/**
|
||||||
gets the latest error if available
|
gets the latest error if available. Clear the existing error
|
||||||
*/
|
*/
|
||||||
static func lastError() -> RustWeldingError?
|
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?
|
static func getLastError() -> String?
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,16 +3,20 @@
|
||||||
// Generated by the Swift generator plugin for the protocol buffer compiler.
|
// Generated by the Swift generator plugin for the protocol buffer compiler.
|
||||||
// Source: compact_formats.proto
|
// 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/
|
// 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 Foundation
|
||||||
import SwiftProtobuf
|
import SwiftProtobuf
|
||||||
|
|
||||||
// If the compiler emits an error on this type, it is because this file
|
// 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
|
// was generated by a version of the `protoc` Swift plug-in that is
|
||||||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
// 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.
|
// that was used to generate this file.
|
||||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||||
|
@ -51,14 +55,14 @@ struct CompactBlock {
|
||||||
init() {}
|
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 {
|
struct CompactTx {
|
||||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
// methods supported on all messages.
|
// 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 index: UInt64 = 0
|
||||||
|
|
||||||
var hash: Data = SwiftProtobuf.Internal.emptyData
|
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";
|
syntax = "proto3";
|
||||||
package cash.z.wallet.sdk.rpc;
|
package cash.z.wallet.sdk.rpc;
|
||||||
option go_package = "walletrpc";
|
option go_package = "walletrpc";
|
||||||
|
@ -19,10 +23,10 @@ message CompactBlock {
|
||||||
repeated CompactTx vtx = 7; // compact transactions from this block
|
repeated CompactTx vtx = 7; // compact transactions from this block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
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.
|
|
||||||
uint64 index = 1;
|
uint64 index = 1;
|
||||||
bytes hash = 2;
|
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";
|
syntax = "proto3";
|
||||||
package cash.z.wallet.sdk.rpc;
|
package cash.z.wallet.sdk.rpc;
|
||||||
option go_package = "walletrpc";
|
option go_package = "walletrpc";
|
||||||
|
@ -5,15 +9,14 @@ option swift_prefix = "";
|
||||||
import "compact_formats.proto";
|
import "compact_formats.proto";
|
||||||
|
|
||||||
// A BlockID message contains identifiers to select a block: a height or a
|
// 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 {
|
message BlockID {
|
||||||
uint64 height = 1;
|
uint64 height = 1;
|
||||||
bytes hash = 2;
|
bytes hash = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockRange technically allows ranging from hash to hash etc but this is not
|
// BlockRange specifies a series of blocks from start to end inclusive.
|
||||||
// currently intended for support, though there is no reason you couldn't do
|
// Both BlockIDs must be heights; specification by hash is not yet supported.
|
||||||
// it. Further permutations are left as an exercise.
|
|
||||||
message BlockRange {
|
message BlockRange {
|
||||||
BlockID start = 1;
|
BlockID start = 1;
|
||||||
BlockID end = 2;
|
BlockID end = 2;
|
||||||
|
@ -21,29 +24,81 @@ message BlockRange {
|
||||||
|
|
||||||
// A TxFilter contains the information needed to identify a particular
|
// A TxFilter contains the information needed to identify a particular
|
||||||
// transaction: either a block and an index, or a direct transaction hash.
|
// transaction: either a block and an index, or a direct transaction hash.
|
||||||
|
// Currently, only specification by hash is supported.
|
||||||
message TxFilter {
|
message TxFilter {
|
||||||
BlockID block = 1;
|
BlockID block = 1;
|
||||||
uint64 index = 2;
|
uint64 index = 2;
|
||||||
bytes hash = 3;
|
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 {
|
message RawTransaction {
|
||||||
bytes data = 1;
|
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 {
|
message SendResponse {
|
||||||
int32 errorCode = 1;
|
int32 errorCode = 1;
|
||||||
string errorMessage = 2;
|
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 {}
|
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 {
|
service CompactTxStreamer {
|
||||||
|
// Compact Blocks
|
||||||
rpc GetLatestBlock(ChainSpec) returns (BlockID) {}
|
rpc GetLatestBlock(ChainSpec) returns (BlockID) {}
|
||||||
rpc GetBlock(BlockID) returns (CompactBlock) {}
|
rpc GetBlock(BlockID) returns (CompactBlock) {}
|
||||||
rpc GetBlockRange(BlockRange) returns (stream CompactBlock) {}
|
rpc GetBlockRange(BlockRange) returns (stream CompactBlock) {}
|
||||||
|
|
||||||
|
// Transactions
|
||||||
rpc GetTransaction(TxFilter) returns (RawTransaction) {}
|
rpc GetTransaction(TxFilter) returns (RawTransaction) {}
|
||||||
rpc SendTransaction(RawTransaction) returns (SendResponse) {}
|
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" }
|
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.
|
/// Instantiate CompactTxStreamerServiceClient, then call methods of this protocol to make API calls.
|
||||||
internal protocol CompactTxStreamerService: ServiceClient {
|
internal protocol CompactTxStreamerService: ServiceClient {
|
||||||
|
@ -97,6 +125,23 @@ internal protocol CompactTxStreamerService: ServiceClient {
|
||||||
@discardableResult
|
@discardableResult
|
||||||
func sendTransaction(_ request: RawTransaction, metadata customMetadata: Metadata, completion: @escaping (SendResponse?, CallResult) -> Void) throws -> CompactTxStreamerSendTransactionCall
|
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 {
|
internal extension CompactTxStreamerService {
|
||||||
|
@ -145,6 +190,31 @@ internal extension CompactTxStreamerService {
|
||||||
return try self.sendTransaction(request, metadata: self.metadata, completion: completion)
|
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 {
|
internal final class CompactTxStreamerServiceClient: ServiceClientBase, CompactTxStreamerService {
|
||||||
|
@ -204,5 +274,37 @@ internal final class CompactTxStreamerServiceClient: ServiceClientBase, CompactT
|
||||||
.start(request: request, metadata: customMetadata, completion: completion)
|
.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.
|
// Generated by the Swift generator plugin for the protocol buffer compiler.
|
||||||
// Source: service.proto
|
// 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/
|
// 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 Foundation
|
||||||
import SwiftProtobuf
|
import SwiftProtobuf
|
||||||
|
|
||||||
// If the compiler emits an error on this type, it is because this file
|
// 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
|
// was generated by a version of the `protoc` Swift plug-in that is
|
||||||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
// 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.
|
// that was used to generate this file.
|
||||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
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
|
/// 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 {
|
struct BlockID {
|
||||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
|
@ -35,68 +39,74 @@ struct BlockID {
|
||||||
init() {}
|
init() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// BlockRange technically allows ranging from hash to hash etc but this is not
|
/// BlockRange specifies a series of blocks from start to end inclusive.
|
||||||
/// currently intended for support, though there is no reason you couldn't do
|
/// Both BlockIDs must be heights; specification by hash is not yet supported.
|
||||||
/// it. Further permutations are left as an exercise.
|
|
||||||
struct BlockRange {
|
struct BlockRange {
|
||||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
// methods supported on all messages.
|
// methods supported on all messages.
|
||||||
|
|
||||||
var start: BlockID {
|
var start: BlockID {
|
||||||
get {return _start ?? BlockID()}
|
get {return _storage._start ?? BlockID()}
|
||||||
set {_start = newValue}
|
set {_uniqueStorage()._start = newValue}
|
||||||
}
|
}
|
||||||
/// Returns true if `start` has been explicitly set.
|
/// 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.
|
/// 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 {
|
var end: BlockID {
|
||||||
get {return _end ?? BlockID()}
|
get {return _storage._end ?? BlockID()}
|
||||||
set {_end = newValue}
|
set {_uniqueStorage()._end = newValue}
|
||||||
}
|
}
|
||||||
/// Returns true if `end` has been explicitly set.
|
/// 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.
|
/// 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()
|
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||||
|
|
||||||
init() {}
|
init() {}
|
||||||
|
|
||||||
fileprivate var _start: BlockID? = nil
|
fileprivate var _storage = _StorageClass.defaultInstance
|
||||||
fileprivate var _end: BlockID? = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A TxFilter contains the information needed to identify a particular
|
/// A TxFilter contains the information needed to identify a particular
|
||||||
/// transaction: either a block and an index, or a direct transaction hash.
|
/// transaction: either a block and an index, or a direct transaction hash.
|
||||||
|
/// Currently, only specification by hash is supported.
|
||||||
struct TxFilter {
|
struct TxFilter {
|
||||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
// methods supported on all messages.
|
// methods supported on all messages.
|
||||||
|
|
||||||
var block: BlockID {
|
var block: BlockID {
|
||||||
get {return _block ?? BlockID()}
|
get {return _storage._block ?? BlockID()}
|
||||||
set {_block = newValue}
|
set {_uniqueStorage()._block = newValue}
|
||||||
}
|
}
|
||||||
/// Returns true if `block` has been explicitly set.
|
/// 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.
|
/// 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()
|
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||||
|
|
||||||
init() {}
|
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 {
|
struct RawTransaction {
|
||||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
|
@ -104,11 +114,16 @@ struct RawTransaction {
|
||||||
|
|
||||||
var data: Data = SwiftProtobuf.Internal.emptyData
|
var data: Data = SwiftProtobuf.Internal.emptyData
|
||||||
|
|
||||||
|
var height: UInt64 = 0
|
||||||
|
|
||||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||||
|
|
||||||
init() {}
|
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 {
|
struct SendResponse {
|
||||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
|
@ -123,7 +138,7 @@ struct SendResponse {
|
||||||
init() {}
|
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 {
|
struct ChainSpec {
|
||||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
|
@ -134,6 +149,102 @@ struct ChainSpec {
|
||||||
init() {}
|
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.
|
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||||
|
|
||||||
fileprivate let _protobuf_package = "cash.z.wallet.sdk.rpc"
|
fileprivate let _protobuf_package = "cash.z.wallet.sdk.rpc"
|
||||||
|
@ -180,29 +291,63 @@ extension BlockRange: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
|
||||||
2: .same(proto: "end"),
|
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 {
|
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||||
|
_ = _uniqueStorage()
|
||||||
|
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||||
switch fieldNumber {
|
switch fieldNumber {
|
||||||
case 1: try decoder.decodeSingularMessageField(value: &self._start)
|
case 1: try decoder.decodeSingularMessageField(value: &_storage._start)
|
||||||
case 2: try decoder.decodeSingularMessageField(value: &self._end)
|
case 2: try decoder.decodeSingularMessageField(value: &_storage._end)
|
||||||
default: break
|
default: break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
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)
|
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 visitor.visitSingularMessageField(value: v, fieldNumber: 2)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
try unknownFields.traverse(visitor: &visitor)
|
try unknownFields.traverse(visitor: &visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func ==(lhs: BlockRange, rhs: BlockRange) -> Bool {
|
static func ==(lhs: BlockRange, rhs: BlockRange) -> Bool {
|
||||||
if lhs._start != rhs._start {return false}
|
if lhs._storage !== rhs._storage {
|
||||||
if lhs._end != rhs._end {return false}
|
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}
|
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -216,34 +361,70 @@ extension TxFilter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
||||||
3: .same(proto: "hash"),
|
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 {
|
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||||
|
_ = _uniqueStorage()
|
||||||
|
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||||
switch fieldNumber {
|
switch fieldNumber {
|
||||||
case 1: try decoder.decodeSingularMessageField(value: &self._block)
|
case 1: try decoder.decodeSingularMessageField(value: &_storage._block)
|
||||||
case 2: try decoder.decodeSingularUInt64Field(value: &self.index)
|
case 2: try decoder.decodeSingularUInt64Field(value: &_storage._index)
|
||||||
case 3: try decoder.decodeSingularBytesField(value: &self.hash)
|
case 3: try decoder.decodeSingularBytesField(value: &_storage._hash)
|
||||||
default: break
|
default: break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
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)
|
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
|
||||||
}
|
}
|
||||||
if self.index != 0 {
|
if _storage._index != 0 {
|
||||||
try visitor.visitSingularUInt64Field(value: self.index, fieldNumber: 2)
|
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)
|
try unknownFields.traverse(visitor: &visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func ==(lhs: TxFilter, rhs: TxFilter) -> Bool {
|
static func ==(lhs: TxFilter, rhs: TxFilter) -> Bool {
|
||||||
if lhs._block != rhs._block {return false}
|
if lhs._storage !== rhs._storage {
|
||||||
if lhs.index != rhs.index {return false}
|
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
|
||||||
if lhs.hash != rhs.hash {return false}
|
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}
|
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -253,12 +434,14 @@ extension RawTransaction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement
|
||||||
static let protoMessageName: String = _protobuf_package + ".RawTransaction"
|
static let protoMessageName: String = _protobuf_package + ".RawTransaction"
|
||||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||||
1: .same(proto: "data"),
|
1: .same(proto: "data"),
|
||||||
|
2: .same(proto: "height"),
|
||||||
]
|
]
|
||||||
|
|
||||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||||
switch fieldNumber {
|
switch fieldNumber {
|
||||||
case 1: try decoder.decodeSingularBytesField(value: &self.data)
|
case 1: try decoder.decodeSingularBytesField(value: &self.data)
|
||||||
|
case 2: try decoder.decodeSingularUInt64Field(value: &self.height)
|
||||||
default: break
|
default: break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,11 +451,15 @@ extension RawTransaction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement
|
||||||
if !self.data.isEmpty {
|
if !self.data.isEmpty {
|
||||||
try visitor.visitSingularBytesField(value: self.data, fieldNumber: 1)
|
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)
|
try unknownFields.traverse(visitor: &visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func ==(lhs: RawTransaction, rhs: RawTransaction) -> Bool {
|
static func ==(lhs: RawTransaction, rhs: RawTransaction) -> Bool {
|
||||||
if lhs.data != rhs.data {return false}
|
if lhs.data != rhs.data {return false}
|
||||||
|
if lhs.height != rhs.height {return false}
|
||||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -331,3 +518,220 @@ extension ChainSpec: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
|
||||||
return true
|
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,
|
time: 1574579149,
|
||||||
tree: "01999fc372390699b15f71d41745abe6a2ea0db4ffa8894d3c5fe30b9261a1a43a01585112668685bd6783cb01b72d17dc86c6d740c27cccf66b75e959e4e4f5ea3710019b7f6b4457a97eadbe1a39bfcc6ba0a56d37010d0d799e1e652fc29733103e04016a0b4d2705e1feb2021d80e5785608536dde05aea5ef676a5427244228b19e2d00010973d03ad5f79fcac64ab3ffbdaaac1a24b74a3617770bf960fb004cbd422439000001984bfce9361025cc38574f944a3ed7b074b3bf88cfce6f14c4a9be4d91d6dc730105871ec1e3737a39bceb00b0c2d253ff36f472e92c361e7ef360d49ea8dc4c4200000001c145105e1bf401668a8f23ca70c47ee92d23bd366072020c83d26b855eeafd6d0001fa6980c053d84f809b6abcf35690f03a11f87b28e3240828e32e3f57af41e54e01319312241b0031e3a255b0d708750b4cb3f3fe79e3503fe488cc8db1dd00753801754bb593ea42d231a7ddf367640f09bbf59dc00f2c1d2003cc340e0c016b5b13"
|
tree: "01999fc372390699b15f71d41745abe6a2ea0db4ffa8894d3c5fe30b9261a1a43a01585112668685bd6783cb01b72d17dc86c6d740c27cccf66b75e959e4e4f5ea3710019b7f6b4457a97eadbe1a39bfcc6ba0a56d37010d0d799e1e652fc29733103e04016a0b4d2705e1feb2021d80e5785608536dde05aea5ef676a5427244228b19e2d00010973d03ad5f79fcac64ab3ffbdaaac1a24b74a3617770bf960fb004cbd422439000001984bfce9361025cc38574f944a3ed7b074b3bf88cfce6f14c4a9be4d91d6dc730105871ec1e3737a39bceb00b0c2d253ff36f472e92c361e7ef360d49ea8dc4c4200000001c145105e1bf401668a8f23ca70c47ee92d23bd366072020c83d26b855eeafd6d0001fa6980c053d84f809b6abcf35690f03a11f87b28e3240828e32e3f57af41e54e01319312241b0031e3a255b0d708750b4cb3f3fe79e3503fe488cc8db1dd00753801754bb593ea42d231a7ddf367640f09bbf59dc00f2c1d2003cc340e0c016b5b13"
|
||||||
)
|
)
|
||||||
case 663000 ..< 663700:
|
case 663000 ..< 663150:
|
||||||
return WalletBirthday(
|
return WalletBirthday(
|
||||||
height: 663000,
|
height: 663000,
|
||||||
hash: "0000000000bd422264b700bb33cab167ab42392c89db0e7c8ce30d57f346fe69",
|
hash: "0000000000bd422264b700bb33cab167ab42392c89db0e7c8ce30d57f346fe69",
|
||||||
time: 1576810013,
|
time: 1576810013,
|
||||||
tree: "0102f02a8cd23e35502f8efa55893c7a145168ac3fa00d4bd032b55097bbe0335a01b57c362e3c834f2216c72ae0d8a335fd2397cc80073d0f5b29c419028bc6c94c100000000157bfd70afa37c8bf0c60c9e160d2145bdfbcf07837b0ff90bf8a5108722cc85400000000011bc9521263584de20822f9483e7edb5af54150c4823c775b2efc6a1eded9625501a6030f8d4b588681eddb66cad63f09c5c7519db49500fc56ebd481ce5e903c22000163f4eec5a2fe00a5f45e71e1542ff01e937d2210c99f03addcce5314a5278b2d0163ab01f46a3bb6ea46f5a19d5bdd59eb3f81e19cfa6d10ab0fd5566c7a16992601fa6980c053d84f809b6abcf35690f03a11f87b28e3240828e32e3f57af41e54e01319312241b0031e3a255b0d708750b4cb3f3fe79e3503fe488cc8db1dd00753801754bb593ea42d231a7ddf367640f09bbf59dc00f2c1d2003cc340e0c016b5b13"
|
tree: "0102f02a8cd23e35502f8efa55893c7a145168ac3fa00d4bd032b55097bbe0335a01b57c362e3c834f2216c72ae0d8a335fd2397cc80073d0f5b29c419028bc6c94c100000000157bfd70afa37c8bf0c60c9e160d2145bdfbcf07837b0ff90bf8a5108722cc85400000000011bc9521263584de20822f9483e7edb5af54150c4823c775b2efc6a1eded9625501a6030f8d4b588681eddb66cad63f09c5c7519db49500fc56ebd481ce5e903c22000163f4eec5a2fe00a5f45e71e1542ff01e937d2210c99f03addcce5314a5278b2d0163ab01f46a3bb6ea46f5a19d5bdd59eb3f81e19cfa6d10ab0fd5566c7a16992601fa6980c053d84f809b6abcf35690f03a11f87b28e3240828e32e3f57af41e54e01319312241b0031e3a255b0d708750b4cb3f3fe79e3503fe488cc8db1dd00753801754bb593ea42d231a7ddf367640f09bbf59dc00f2c1d2003cc340e0c016b5b13"
|
||||||
)
|
)
|
||||||
|
case 663150 ..< 663700:
|
||||||
|
return WalletBirthday(
|
||||||
|
height: 663150,
|
||||||
|
hash: "0000000002fd3be4c24c437bd22620901617125ec2a3a6c902ec9a6c06f734fc",
|
||||||
|
time: 1576821833,
|
||||||
|
tree: "01ec6278a1bed9e1b080fd60ef50eb17411645e3746ff129283712bc4757ecc833001001b4e1d4a26ac4a2810b57a14f4ffb69395f55dde5674ecd2462af96f9126e054701a36afb68534f640938bdffd80dfcb3f4d5e232488abbf67d049b33a761e7ed6901a16e35205fb7fe626a9b13fc43e1d2b98a9c241f99f93d5e93a735454073025401f5b9bcbf3d0e3c83f95ee79299e8aeadf30af07717bda15ffb7a3d00243b58570001fa6d4c2390e205f81d86b85ace0b48f3ce0afb78eeef3e14c70bcfd7c5f0191c0000011bc9521263584de20822f9483e7edb5af54150c4823c775b2efc6a1eded9625501a6030f8d4b588681eddb66cad63f09c5c7519db49500fc56ebd481ce5e903c22000163f4eec5a2fe00a5f45e71e1542ff01e937d2210c99f03addcce5314a5278b2d0163ab01f46a3bb6ea46f5a19d5bdd59eb3f81e19cfa6d10ab0fd5566c7a16992601fa6980c053d84f809b6abcf35690f03a11f87b28e3240828e32e3f57af41e54e01319312241b0031e3a255b0d708750b4cb3f3fe79e3503fe488cc8db1dd00753801754bb593ea42d231a7ddf367640f09bbf59dc00f2c1d2003cc340e0c016b5b13"
|
||||||
|
)
|
||||||
case 663700 ..< 670000:
|
case 663700 ..< 670000:
|
||||||
return WalletBirthday(
|
return WalletBirthday(
|
||||||
height: 663700,
|
height: 663700,
|
||||||
|
|
|
@ -64,7 +64,6 @@ public extension Notification.Name {
|
||||||
*/
|
*/
|
||||||
public class SDKSynchronizer: Synchronizer {
|
public class SDKSynchronizer: Synchronizer {
|
||||||
|
|
||||||
|
|
||||||
public struct NotificationKeys {
|
public struct NotificationKeys {
|
||||||
public static let progress = "SDKSynchronizer.progress"
|
public static let progress = "SDKSynchronizer.progress"
|
||||||
public static let blockHeight = "SDKSynchronizer.blockHeight"
|
public static let blockHeight = "SDKSynchronizer.blockHeight"
|
||||||
|
|
|
@ -86,7 +86,7 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFailure() {
|
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)
|
let expect = XCTestExpectation(description: self.description)
|
||||||
expect.expectedFulfillmentCount = 1
|
expect.expectedFulfillmentCount = 1
|
||||||
|
|
|
@ -18,7 +18,7 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
var startedScanningNotificationExpectation: XCTestExpectation!
|
var startedScanningNotificationExpectation: XCTestExpectation!
|
||||||
var startedValidatingNotificationExpectation: XCTestExpectation!
|
var startedValidatingNotificationExpectation: XCTestExpectation!
|
||||||
var idleNotificationExpectation: XCTestExpectation!
|
var idleNotificationExpectation: XCTestExpectation!
|
||||||
let mockLatestHeight = 282_000
|
let mockLatestHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 2000
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
|
@ -108,27 +108,24 @@ class CompactBlockProcessorTests: XCTestCase {
|
||||||
|
|
||||||
// test first range
|
// test first range
|
||||||
var latestDownloadedHeight = processorConfig.walletBirthday // this can be either this or Wallet Birthday.
|
var latestDownloadedHeight = processorConfig.walletBirthday // this can be either this or Wallet Birthday.
|
||||||
var latestBlockchainHeight = BlockHeight(281_000)
|
var latestBlockchainHeight = BlockHeight(ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 1000)
|
||||||
|
|
||||||
var expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight, upper:latestDownloadedHeight + processorConfig.downloadBatchSize - 1))
|
var expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight, upper:latestDownloadedHeight + processorConfig.downloadBatchSize - 1))
|
||||||
|
|
||||||
XCTAssertEqual(expectedBatchRange, processor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight))
|
XCTAssertEqual(expectedBatchRange, processor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight))
|
||||||
|
|
||||||
// Test mid-range
|
// Test mid-range
|
||||||
latestDownloadedHeight = BlockHeight(280_100)
|
latestDownloadedHeight = BlockHeight(ZcashSDK.SAPLING_ACTIVATION_HEIGHT + ZcashSDK.DEFAULT_BATCH_SIZE)
|
||||||
latestBlockchainHeight = BlockHeight(281_000)
|
latestBlockchainHeight = BlockHeight(ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 1000)
|
||||||
|
|
||||||
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper:latestDownloadedHeight + processorConfig.downloadBatchSize))
|
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper:latestDownloadedHeight + processorConfig.downloadBatchSize))
|
||||||
|
|
||||||
XCTAssertEqual(expectedBatchRange, processor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight))
|
XCTAssertEqual(expectedBatchRange, processor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight))
|
||||||
|
|
||||||
latestDownloadedHeight = BlockHeight(280_950)
|
|
||||||
latestBlockchainHeight = BlockHeight(281_000)
|
|
||||||
|
|
||||||
// Test last batch range
|
// Test last batch range
|
||||||
|
|
||||||
latestDownloadedHeight = BlockHeight(280_950)
|
latestDownloadedHeight = BlockHeight(ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 950)
|
||||||
latestBlockchainHeight = BlockHeight(281_000)
|
latestBlockchainHeight = BlockHeight(ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 1000)
|
||||||
|
|
||||||
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))
|
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
var startedValidatingNotificationExpectation: XCTestExpectation!
|
var startedValidatingNotificationExpectation: XCTestExpectation!
|
||||||
var idleNotificationExpectation: XCTestExpectation!
|
var idleNotificationExpectation: XCTestExpectation!
|
||||||
var reorgNotificationExpectation: XCTestExpectation!
|
var reorgNotificationExpectation: XCTestExpectation!
|
||||||
let mockLatestHeight = 282_000
|
let mockLatestHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 2000
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
|
@ -33,7 +33,7 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
let mockBackend = MockRustBackend.self
|
let mockBackend = MockRustBackend.self
|
||||||
mockBackend.mockValidateCombinedChainFailAfterAttempts = 3
|
mockBackend.mockValidateCombinedChainFailAfterAttempts = 3
|
||||||
mockBackend.mockValidateCombinedChainKeepFailing = false
|
mockBackend.mockValidateCombinedChainKeepFailing = false
|
||||||
mockBackend.mockValidateCombinedChainFailureHeight = 280_320
|
mockBackend.mockValidateCombinedChainFailureHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 320
|
||||||
|
|
||||||
processor = CompactBlockProcessor(downloader: downloader,
|
processor = CompactBlockProcessor(downloader: downloader,
|
||||||
backend: mockBackend,
|
backend: mockBackend,
|
||||||
|
@ -65,7 +65,7 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func processorHandledReorg(_ notification: Notification) {
|
@objc func processorHandledReorg(_ notification: Notification) {
|
||||||
// DispatchQueue.main.sync {
|
|
||||||
XCTAssertNotNil(notification.userInfo)
|
XCTAssertNotNil(notification.userInfo)
|
||||||
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
|
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
|
||||||
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
|
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
|
||||||
|
@ -76,8 +76,6 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
} else {
|
} else {
|
||||||
XCTFail("CompactBlockProcessor reorg notification is malformed")
|
XCTFail("CompactBlockProcessor reorg notification is malformed")
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func processorFailed(_ notification: Notification) {
|
@objc func processorFailed(_ notification: Notification) {
|
||||||
|
@ -88,7 +86,6 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
} else {
|
} else {
|
||||||
XCTFail("CompactBlockProcessor failed")
|
XCTFail("CompactBlockProcessor failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,10 +112,9 @@ class CompactBlockReorgTests: XCTestCase {
|
||||||
downloadStartedExpect,
|
downloadStartedExpect,
|
||||||
startedValidatingNotificationExpectation,
|
startedValidatingNotificationExpectation,
|
||||||
startedScanningNotificationExpectation,
|
startedScanningNotificationExpectation,
|
||||||
|
|
||||||
reorgNotificationExpectation,
|
reorgNotificationExpectation,
|
||||||
idleNotificationExpectation,
|
idleNotificationExpectation,
|
||||||
], timeout: 3000,enforceOrder: true)
|
], timeout: 300,enforceOrder: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func expectedBatches(currentHeight: BlockHeight, targetHeight: BlockHeight, batchSize: Int) -> Int {
|
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
|
nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func decryptAndStoreTransaction(dbData: URL, tx: [UInt8]) -> Bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ class LightWalletEndpointBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChannelProvider {
|
class ChannelProvider {
|
||||||
func channel() -> SwiftGRPC.Channel {
|
func channel(secure: Bool = false) -> SwiftGRPC.Channel {
|
||||||
Channel(address: Constants.address, secure: false)
|
Channel(address: Constants.address, secure: secure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue