Merge branch 'master' into merge_master_to_zip_316
This commit is contained in:
commit
d737ddefa9
|
@ -30,7 +30,7 @@ enum DemoAppConfig {
|
|||
}()
|
||||
|
||||
static var endpoint: LightWalletEndpoint {
|
||||
return LightWalletEndpoint(address: self.host, port: self.port, secure: true)
|
||||
return LightWalletEndpoint(address: self.host, port: self.port, secure: true, streamingCallTimeoutInMillis: 10 * 60 * 60 * 1000)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,18 +28,13 @@ class LatestHeightViewController: UIViewController {
|
|||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
service.latestBlockHeight { result in
|
||||
switch result {
|
||||
case .success(let height):
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.model = height
|
||||
}
|
||||
|
||||
case .failure(let error):
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.fail(error)
|
||||
}
|
||||
|
||||
/// Note: It's safe to modify model or call fail() because all methods of a UIViewController are MainActor methods by default.
|
||||
Task {
|
||||
do {
|
||||
model = try await service.latestBlockHeightAsync()
|
||||
} catch {
|
||||
fail(error as? LightWalletServiceError ?? .unknown)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
// swift-tools-version:5.5
|
||||
// swift-tools-version:5.6
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "ZcashLightClientKit",
|
||||
platforms: [
|
||||
.iOS(.v13),
|
||||
.macOS(.v10_12)
|
||||
.macOS(.v10_15)
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
|
|
|
@ -85,39 +85,28 @@ extension CompactBlockStorage: CompactBlockRepository {
|
|||
try latestBlockHeight()
|
||||
}
|
||||
|
||||
func latestHeight(result: @escaping (Swift.Result<BlockHeight, Error>) -> Void) {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
do {
|
||||
result(.success(try self.latestBlockHeight()))
|
||||
} catch {
|
||||
result(.failure(error))
|
||||
}
|
||||
func latestHeightAsync() async throws -> BlockHeight {
|
||||
let task = Task(priority: .userInitiated) {
|
||||
try latestBlockHeight()
|
||||
}
|
||||
return try await task.value
|
||||
}
|
||||
|
||||
|
||||
func write(blocks: [ZcashCompactBlock]) throws {
|
||||
try insert(blocks)
|
||||
}
|
||||
|
||||
func write(blocks: [ZcashCompactBlock], completion: ((Error?) -> Void)?) {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
do {
|
||||
try self.insert(blocks)
|
||||
completion?(nil)
|
||||
} catch {
|
||||
completion?(error)
|
||||
}
|
||||
func writeAsync(blocks: [ZcashCompactBlock]) async throws {
|
||||
let task = Task(priority: .userInitiated) {
|
||||
try insert(blocks)
|
||||
}
|
||||
try await task.value
|
||||
}
|
||||
|
||||
func rewind(to height: BlockHeight, completion: ((Error?) -> Void)?) {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
do {
|
||||
try self.rewind(to: height)
|
||||
completion?(nil)
|
||||
} catch {
|
||||
completion?(error)
|
||||
}
|
||||
|
||||
func rewindAsync(to height: BlockHeight) async throws {
|
||||
let task = Task(priority: .userInitiated) {
|
||||
try rewind(to: height)
|
||||
}
|
||||
try await task.value
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,59 +16,55 @@ enum CompactBlockDownloadError: Error {
|
|||
Represents what a compact block downloaded should provide to its clients
|
||||
*/
|
||||
public protocol CompactBlockDownloading {
|
||||
/**
|
||||
Downloads and stores the given block range.
|
||||
Non-Blocking
|
||||
*/
|
||||
func downloadBlockRange(
|
||||
_ heightRange: CompactBlockRange,
|
||||
completion: @escaping (Error?) -> Void
|
||||
)
|
||||
|
||||
/**
|
||||
Remove newer blocks and go back to the given height
|
||||
- Parameters:
|
||||
- height: the given height to rewind to
|
||||
- completion: block to be executed after completing rewind
|
||||
*/
|
||||
func rewind(to height: BlockHeight, completion: @escaping (Error?) -> Void)
|
||||
|
||||
/**
|
||||
returns the height of the latest compact block stored locally
|
||||
BlockHeight.empty() if no blocks are stored yet
|
||||
non-blocking
|
||||
*/
|
||||
func lastDownloadedBlockHeight(result: @escaping (Result<BlockHeight, Error>) -> Void)
|
||||
|
||||
/**
|
||||
Returns the last height on the blockchain
|
||||
Non-blocking
|
||||
*/
|
||||
func latestBlockHeight(result: @escaping (Result<BlockHeight, Error>) -> Void)
|
||||
|
||||
/**
|
||||
Downloads and stores the given block range.
|
||||
Blocking
|
||||
*/
|
||||
func downloadBlockRange(_ range: CompactBlockRange) throws
|
||||
|
||||
|
||||
/**
|
||||
Downloads and stores the given block range.
|
||||
Non-Blocking
|
||||
*/
|
||||
func downloadBlockRangeAsync(_ heightRange: CompactBlockRange) async throws
|
||||
|
||||
/**
|
||||
Restore the download progress up to the given height.
|
||||
*/
|
||||
func rewind(to height: BlockHeight) throws
|
||||
|
||||
/**
|
||||
Remove newer blocks and go back to the given height
|
||||
- Parameter height: the given height to rewind to
|
||||
*/
|
||||
func rewindAsync(to height: BlockHeight) async throws
|
||||
|
||||
/**
|
||||
Returns the height of the latest compact block stored locally.
|
||||
BlockHeight.empty() if no blocks are stored yet
|
||||
Blocking
|
||||
*/
|
||||
func lastDownloadedBlockHeight() throws -> BlockHeight
|
||||
|
||||
|
||||
/**
|
||||
returns the height of the latest compact block stored locally
|
||||
BlockHeight.empty() if no blocks are stored yet
|
||||
non-blocking
|
||||
*/
|
||||
func lastDownloadedBlockHeightAsync() async throws -> BlockHeight
|
||||
|
||||
/**
|
||||
Returns the latest block height
|
||||
Blocking
|
||||
*/
|
||||
func latestBlockHeight() throws -> BlockHeight
|
||||
|
||||
/**
|
||||
Returns the last height on the blockchain
|
||||
Non-blocking
|
||||
*/
|
||||
func latestBlockHeightAsync() async throws -> BlockHeight
|
||||
|
||||
/**
|
||||
Gets the transaction for the Id given
|
||||
|
@ -81,17 +77,30 @@ public protocol CompactBlockDownloading {
|
|||
/**
|
||||
Gets the transaction for the Id given
|
||||
- Parameter txId: Data representing the transaction Id
|
||||
- Parameter result: a handler for the result of the operation
|
||||
*/
|
||||
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, Error>) -> Void)
|
||||
|
||||
func fetchTransactionAsync(txId: Data) async throws -> TransactionEntity
|
||||
|
||||
func fetchUnspentTransactionOutputs(tAddress: String, startHeight: BlockHeight) throws -> [UnspentTransactionOutputEntity]
|
||||
|
||||
// TODO: will be removed with the issue 474
|
||||
// https://github.com/zcash/ZcashLightClientKit/issues/474
|
||||
// Use the new API fetchUnspentTransactionOutputs(...) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error>
|
||||
func fetchUnspentTransactionOutputs(tAddress: String, startHeight: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], Error>) -> Void)
|
||||
|
||||
func fetchUnspentTransactionOutputs(tAddress: String, startHeight: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error>
|
||||
|
||||
func fetchUnspentTransactionOutputs(tAddresses: [String], startHeight: BlockHeight) throws -> [UnspentTransactionOutputEntity]
|
||||
|
||||
func fetchUnspentTransactionOutputs(tAddresses: [String], startHeight: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], Error>) -> Void)
|
||||
// TODO: will be removed with the issue 474
|
||||
// https://github.com/zcash/ZcashLightClientKit/issues/474
|
||||
// Use the new API fetchUnspentTransactionOutputs(...) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error>
|
||||
func fetchUnspentTransactionOutputs(
|
||||
tAddresses: [String],
|
||||
startHeight: BlockHeight,
|
||||
result: @escaping (Result<[UnspentTransactionOutputEntity], Error>) -> Void
|
||||
)
|
||||
|
||||
func fetchUnspentTransactionOutputs(tAddresses: [String], startHeight: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error>
|
||||
|
||||
func closeConnection()
|
||||
}
|
||||
|
@ -137,6 +146,10 @@ extension CompactBlockDownloader: CompactBlockDownloading {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fetchUnspentTransactionOutputs(tAddresses: [String], startHeight: BlockHeight ) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
||||
lightwalletService.fetchUTXOs(for: tAddresses, height: startHeight)
|
||||
}
|
||||
|
||||
func fetchUnspentTransactionOutputs(tAddress: String, startHeight: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
||||
try lightwalletService.fetchUTXOs(for: tAddress, height: startHeight)
|
||||
|
@ -153,68 +166,54 @@ extension CompactBlockDownloader: CompactBlockDownloading {
|
|||
}
|
||||
}
|
||||
|
||||
func latestBlockHeight(result: @escaping (Result<BlockHeight, Error>) -> Void) {
|
||||
lightwalletService.latestBlockHeight { fetchResult in
|
||||
switch fetchResult {
|
||||
case .failure(let error):
|
||||
result(.failure(error))
|
||||
case .success(let height):
|
||||
result(.success(height))
|
||||
}
|
||||
}
|
||||
func fetchUnspentTransactionOutputs(tAddress: String, startHeight: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
||||
lightwalletService.fetchUTXOs(for: tAddress, height: startHeight)
|
||||
}
|
||||
|
||||
func latestBlockHeightAsync() async throws -> BlockHeight {
|
||||
try await lightwalletService.latestBlockHeightAsync()
|
||||
}
|
||||
|
||||
func latestBlockHeight() throws -> BlockHeight {
|
||||
try lightwalletService.latestBlockHeight()
|
||||
}
|
||||
|
||||
/**
|
||||
Downloads and stores the given block range.
|
||||
Non-Blocking
|
||||
*/
|
||||
func downloadBlockRange(
|
||||
_ heightRange: CompactBlockRange,
|
||||
completion: @escaping (Error?) -> Void
|
||||
) {
|
||||
lightwalletService.blockRange(heightRange) { [weak self] result in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
completion(error)
|
||||
case .success(let compactBlocks):
|
||||
self.storage.write(blocks: compactBlocks) { storeError in
|
||||
completion(storeError)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func downloadBlockRange(_ range: CompactBlockRange) throws {
|
||||
let blocks = try lightwalletService.blockRange(range)
|
||||
try storage.write(blocks: blocks)
|
||||
}
|
||||
|
||||
func rewind(to height: BlockHeight, completion: @escaping (Error?) -> Void) {
|
||||
storage.rewind(to: height) { e in
|
||||
completion(e)
|
||||
}
|
||||
}
|
||||
|
||||
func lastDownloadedBlockHeight(result: @escaping (Result<BlockHeight, Error>) -> Void) {
|
||||
storage.latestHeight { heightResult in
|
||||
switch heightResult {
|
||||
case .failure(let e):
|
||||
result(.failure(CompactBlockDownloadError.generalError(error: e)))
|
||||
return
|
||||
case .success(let height):
|
||||
result(.success(height))
|
||||
|
||||
func downloadBlockRangeAsync( _ heightRange: CompactBlockRange) async throws {
|
||||
let stream: AsyncThrowingStream<ZcashCompactBlock, Error> = lightwalletService.blockRange(heightRange)
|
||||
do {
|
||||
var compactBlocks: [ZcashCompactBlock] = []
|
||||
for try await compactBlock in stream {
|
||||
compactBlocks.append(compactBlock)
|
||||
}
|
||||
try await self.storage.writeAsync(blocks: compactBlocks)
|
||||
} catch {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
func rewindAsync(to height: BlockHeight) async throws {
|
||||
do {
|
||||
try await storage.rewindAsync(to: height)
|
||||
} catch {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
func lastDownloadedBlockHeightAsync() async throws -> BlockHeight {
|
||||
do {
|
||||
let latestHeight = try await storage.latestHeightAsync()
|
||||
return latestHeight
|
||||
} catch {
|
||||
throw CompactBlockDownloadError.generalError(error: error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func rewind(to height: BlockHeight) throws {
|
||||
try self.storage.rewind(to: height)
|
||||
}
|
||||
|
@ -227,14 +226,7 @@ extension CompactBlockDownloader: CompactBlockDownloading {
|
|||
try lightwalletService.fetchTransaction(txId: txId)
|
||||
}
|
||||
|
||||
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, Error>) -> Void) {
|
||||
lightwalletService.fetchTransaction(txId: txId) { txResult in
|
||||
switch txResult {
|
||||
case .failure(let error):
|
||||
result(.failure(error))
|
||||
case .success(let transaction):
|
||||
result(.success(transaction))
|
||||
}
|
||||
}
|
||||
func fetchTransactionAsync(txId: Data) async throws -> TransactionEntity {
|
||||
try await lightwalletService.fetchTransactionAsync(txId: txId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,9 @@ class CompactBlockDownloadOperation: ZcashOperation {
|
|||
|
||||
private var downloader: CompactBlockDownloading
|
||||
private var range: CompactBlockRange
|
||||
|
||||
private var cancelableTask: Task<Void, Error>?
|
||||
private var done = false
|
||||
|
||||
required init(downloader: CompactBlockDownloading, range: CompactBlockRange) {
|
||||
self.range = range
|
||||
self.downloader = downloader
|
||||
|
@ -28,12 +30,29 @@ class CompactBlockDownloadOperation: ZcashOperation {
|
|||
return
|
||||
}
|
||||
self.startedHandler?()
|
||||
do {
|
||||
try downloader.downloadBlockRange(range)
|
||||
} catch {
|
||||
self.error = error
|
||||
self.fail()
|
||||
|
||||
cancelableTask = Task {
|
||||
do {
|
||||
try await downloader.downloadBlockRangeAsync(range)
|
||||
self.done = true
|
||||
} catch {
|
||||
self.fail(error: error)
|
||||
}
|
||||
}
|
||||
|
||||
while !done && !isCancelled {
|
||||
sleep(1)
|
||||
}
|
||||
}
|
||||
|
||||
override func fail(error: Error? = nil) {
|
||||
self.cancelableTask?.cancel()
|
||||
super.fail(error: error)
|
||||
}
|
||||
|
||||
override func cancel() {
|
||||
self.cancelableTask?.cancel()
|
||||
super.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +71,7 @@ class CompactBlockStreamDownloadOperation: ZcashOperation {
|
|||
private var storage: CompactBlockStorage
|
||||
private var service: LightWalletService
|
||||
private var done = false
|
||||
private var cancelable: CancellableCall?
|
||||
private var cancelableTask: Task<Void, Error>?
|
||||
private var startHeight: BlockHeight?
|
||||
private var targetHeight: BlockHeight?
|
||||
private var blockBufferSize: Int
|
||||
|
@ -93,71 +112,61 @@ class CompactBlockStreamDownloadOperation: ZcashOperation {
|
|||
self.name = "Download Stream Operation"
|
||||
}
|
||||
|
||||
// swiftlint:disable cyclomatic_complexity
|
||||
override func main() {
|
||||
guard !shouldCancel() else {
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
self.startedHandler?()
|
||||
do {
|
||||
if self.targetHeight == nil {
|
||||
self.targetHeight = try service.latestBlockHeight()
|
||||
}
|
||||
guard let latestHeight = self.targetHeight else {
|
||||
throw LightWalletServiceError.generalError(message: "missing target height on block stream operation")
|
||||
}
|
||||
let latestDownloaded = try storage.latestHeight()
|
||||
let startHeight = max(self.startHeight ?? BlockHeight.empty(), latestDownloaded)
|
||||
|
||||
self.cancelable = self.service.blockStream(startHeight: startHeight, endHeight: latestHeight) { [weak self] blockResult in
|
||||
switch blockResult {
|
||||
case .success(let result):
|
||||
switch result {
|
||||
case .success:
|
||||
do {
|
||||
try self?.flush()
|
||||
self?.done = true
|
||||
} catch {
|
||||
self?.fail(error: error)
|
||||
}
|
||||
return
|
||||
case .error(let e):
|
||||
self?.fail(error: e)
|
||||
}
|
||||
case .failure(let e):
|
||||
if case .userCancelled = e {
|
||||
self?.done = true
|
||||
} else {
|
||||
self?.fail(error: e)
|
||||
}
|
||||
|
||||
cancelableTask = Task {
|
||||
do {
|
||||
if self.targetHeight == nil {
|
||||
self.targetHeight = try await service.latestBlockHeightAsync()
|
||||
}
|
||||
} handler: {[weak self] block in
|
||||
guard let self = self else { return }
|
||||
do {
|
||||
try self.cache(block, flushCache: false)
|
||||
} catch {
|
||||
guard let latestHeight = self.targetHeight else {
|
||||
throw LightWalletServiceError.generalError(message: "missing target height on block stream operation")
|
||||
}
|
||||
let latestDownloaded = try await storage.latestHeightAsync()
|
||||
let startHeight = max(self.startHeight ?? BlockHeight.empty(), latestDownloaded)
|
||||
|
||||
let stream = service.blockStream(
|
||||
startHeight: startHeight,
|
||||
endHeight: latestHeight
|
||||
)
|
||||
|
||||
for try await zcashCompactBlock in stream {
|
||||
try self.cache(zcashCompactBlock, flushCache: false)
|
||||
let progress = BlockProgress(
|
||||
startHeight: startHeight,
|
||||
targetHeight: latestHeight,
|
||||
progressHeight: zcashCompactBlock.height
|
||||
)
|
||||
self.progressDelegate?.progressUpdated(.download(progress))
|
||||
}
|
||||
try self.flush()
|
||||
self.done = true
|
||||
} catch {
|
||||
if let err = error as? LightWalletServiceError, case .userCancelled = err {
|
||||
self.done = true
|
||||
} else {
|
||||
self.fail(error: error)
|
||||
}
|
||||
} progress: { progress in
|
||||
self.progressDelegate?.progressUpdated(.download(progress))
|
||||
}
|
||||
|
||||
while !done && !isCancelled {
|
||||
sleep(1)
|
||||
}
|
||||
} catch {
|
||||
self.fail(error: error)
|
||||
}
|
||||
|
||||
while !done && !isCancelled {
|
||||
sleep(1)
|
||||
}
|
||||
}
|
||||
|
||||
override func fail(error: Error? = nil) {
|
||||
self.cancelable?.cancel()
|
||||
self.cancelableTask?.cancel()
|
||||
super.fail(error: error)
|
||||
}
|
||||
|
||||
override func cancel() {
|
||||
self.cancelable?.cancel()
|
||||
self.cancelableTask?.cancel()
|
||||
super.cancel()
|
||||
}
|
||||
|
||||
|
@ -185,10 +194,11 @@ class CompactBlockBatchDownloadOperation: ZcashOperation {
|
|||
override var isAsynchronous: Bool { false }
|
||||
|
||||
private var batch: Int
|
||||
private var done = false
|
||||
private var maxRetries: Int
|
||||
private var storage: CompactBlockStorage
|
||||
private var service: LightWalletService
|
||||
private var cancelable: CancellableCall?
|
||||
private var cancelableTask: Task<Void, Error>?
|
||||
private var startHeight: BlockHeight
|
||||
private var targetHeight: BlockHeight
|
||||
|
||||
|
@ -220,72 +230,85 @@ class CompactBlockBatchDownloadOperation: ZcashOperation {
|
|||
return
|
||||
}
|
||||
self.startedHandler?()
|
||||
do {
|
||||
let localDownloadedHeight = try self.storage.latestHeight()
|
||||
|
||||
if localDownloadedHeight != BlockHeight.empty() && localDownloadedHeight > startHeight {
|
||||
LoggerProxy.warn("provided startHeight (\(startHeight)) differs from local latest downloaded height (\(localDownloadedHeight))")
|
||||
startHeight = localDownloadedHeight + 1
|
||||
}
|
||||
|
||||
var currentHeight = startHeight
|
||||
self.progressDelegate?.progressUpdated(
|
||||
.download(
|
||||
BlockProgress(
|
||||
startHeight: currentHeight,
|
||||
targetHeight: targetHeight,
|
||||
progressHeight: currentHeight
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
while !isCancelled && currentHeight <= targetHeight {
|
||||
var retries = 0
|
||||
var success = true
|
||||
var localError: Error?
|
||||
|
||||
let range = nextRange(currentHeight: currentHeight, targetHeight: targetHeight)
|
||||
|
||||
cancelableTask = Task {
|
||||
do {
|
||||
let localDownloadedHeight = try await self.storage.latestHeightAsync()
|
||||
|
||||
repeat {
|
||||
do {
|
||||
let blocks = try service.blockRange(range)
|
||||
try storage.insert(blocks)
|
||||
success = true
|
||||
} catch {
|
||||
success = false
|
||||
localError = error
|
||||
retries += 1
|
||||
}
|
||||
} while !isCancelled && !success && retries < maxRetries
|
||||
|
||||
if retries >= maxRetries {
|
||||
throw CompactBlockBatchDownloadOperationError.batchDownloadFailed(range: range, error: localError)
|
||||
if localDownloadedHeight != BlockHeight.empty() && localDownloadedHeight > startHeight {
|
||||
LoggerProxy.warn("provided startHeight (\(startHeight)) differs from local latest downloaded height (\(localDownloadedHeight))")
|
||||
startHeight = localDownloadedHeight + 1
|
||||
}
|
||||
|
||||
var currentHeight = startHeight
|
||||
self.progressDelegate?.progressUpdated(
|
||||
.download(
|
||||
BlockProgress(
|
||||
startHeight: startHeight,
|
||||
startHeight: currentHeight,
|
||||
targetHeight: targetHeight,
|
||||
progressHeight: range.upperBound
|
||||
progressHeight: currentHeight
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
while !isCancelled && currentHeight <= targetHeight {
|
||||
var retries = 0
|
||||
var success = true
|
||||
var localError: Error?
|
||||
|
||||
let range = nextRange(currentHeight: currentHeight, targetHeight: targetHeight)
|
||||
|
||||
repeat {
|
||||
do {
|
||||
let stream: AsyncThrowingStream<ZcashCompactBlock, Error> = service.blockRange(range)
|
||||
|
||||
currentHeight = range.upperBound + 1
|
||||
var blocks: [ZcashCompactBlock] = []
|
||||
for try await compactBlock in stream {
|
||||
blocks.append(compactBlock)
|
||||
}
|
||||
try storage.insert(blocks)
|
||||
success = true
|
||||
} catch {
|
||||
success = false
|
||||
localError = error
|
||||
retries += 1
|
||||
}
|
||||
} while !isCancelled && !success && retries < maxRetries
|
||||
|
||||
if retries >= maxRetries {
|
||||
throw CompactBlockBatchDownloadOperationError.batchDownloadFailed(range: range, error: localError)
|
||||
}
|
||||
|
||||
self.progressDelegate?.progressUpdated(
|
||||
.download(
|
||||
BlockProgress(
|
||||
startHeight: startHeight,
|
||||
targetHeight: targetHeight,
|
||||
progressHeight: range.upperBound
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
currentHeight = range.upperBound + 1
|
||||
}
|
||||
self.done = true
|
||||
} catch {
|
||||
self.fail(error: error)
|
||||
}
|
||||
} catch {
|
||||
self.fail(error: error)
|
||||
}
|
||||
|
||||
while !done && !isCancelled {
|
||||
sleep(1)
|
||||
}
|
||||
}
|
||||
|
||||
override func fail(error: Error? = nil) {
|
||||
self.cancelable?.cancel()
|
||||
self.cancelableTask?.cancel()
|
||||
super.fail(error: error)
|
||||
}
|
||||
|
||||
override func cancel() {
|
||||
self.cancelable?.cancel()
|
||||
self.cancelableTask?.cancel()
|
||||
super.cancel()
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,9 @@ class CompactBlockEnhancementOperation: ZcashOperation {
|
|||
private(set) var network: NetworkType
|
||||
private weak var progressDelegate: CompactBlockProgressDelegate?
|
||||
private var dataDb: URL
|
||||
|
||||
private var cancelableTask: Task<Void, Error>?
|
||||
private var done = false
|
||||
|
||||
init(
|
||||
rustWelding: ZcashRustBackendWelding.Type,
|
||||
dataDb: URL,
|
||||
|
@ -58,44 +60,50 @@ class CompactBlockEnhancementOperation: ZcashOperation {
|
|||
|
||||
self.startedHandler?()
|
||||
|
||||
// fetch transactions
|
||||
do {
|
||||
guard let transactions = try repository.findTransactions(in: self.range, limit: Int.max), !transactions.isEmpty else {
|
||||
LoggerProxy.debug("no transactions detected on range: \(range.printRange)")
|
||||
return
|
||||
}
|
||||
|
||||
for index in 0 ..< transactions.count {
|
||||
let transaction = transactions[index]
|
||||
var retry = true
|
||||
|
||||
while retry && self.retries < maxRetries {
|
||||
do {
|
||||
let confirmedTx = try enhance(transaction: transaction)
|
||||
retry = false
|
||||
self.reportProgress(
|
||||
totalTransactions: transactions.count,
|
||||
enhanced: index + 1,
|
||||
txEnhanced: confirmedTx
|
||||
)
|
||||
} catch {
|
||||
self.retries += 1
|
||||
LoggerProxy.error("could not enhance txId \(transaction.transactionId.toHexStringTxId()) - Error: \(error)")
|
||||
if retries > maxRetries {
|
||||
throw error
|
||||
cancelableTask = Task {
|
||||
// fetch transactions
|
||||
do {
|
||||
guard let transactions = try repository.findTransactions(in: self.range, limit: Int.max), !transactions.isEmpty else {
|
||||
LoggerProxy.debug("no transactions detected on range: \(range.printRange)")
|
||||
return
|
||||
}
|
||||
|
||||
for index in 0 ..< transactions.count {
|
||||
let transaction = transactions[index]
|
||||
var retry = true
|
||||
|
||||
while retry && self.retries < maxRetries {
|
||||
do {
|
||||
let confirmedTx = try await enhance(transaction: transaction)
|
||||
retry = false
|
||||
self.reportProgress(
|
||||
totalTransactions: transactions.count,
|
||||
enhanced: index + 1,
|
||||
txEnhanced: confirmedTx
|
||||
)
|
||||
} catch {
|
||||
self.retries += 1
|
||||
LoggerProxy.error("could not enhance txId \(transaction.transactionId.toHexStringTxId()) - Error: \(error)")
|
||||
if retries > maxRetries {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
LoggerProxy.error("error enhancing transactions! \(error)")
|
||||
self.fail(error: error)
|
||||
return
|
||||
}
|
||||
} catch {
|
||||
LoggerProxy.error("error enhancing transactions! \(error)")
|
||||
self.error = error
|
||||
self.fail()
|
||||
return
|
||||
|
||||
if let handler = self.txFoundHandler, let foundTxs = try? repository.findConfirmedTransactions(in: self.range, offset: 0, limit: Int.max) {
|
||||
handler(foundTxs, self.range)
|
||||
}
|
||||
self.done = true
|
||||
}
|
||||
|
||||
if let handler = self.txFoundHandler, let foundTxs = try? repository.findConfirmedTransactions(in: self.range, offset: 0, limit: Int.max) {
|
||||
handler(foundTxs, self.range)
|
||||
while !done && !isCancelled {
|
||||
sleep(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,10 +120,10 @@ class CompactBlockEnhancementOperation: ZcashOperation {
|
|||
)
|
||||
}
|
||||
|
||||
func enhance(transaction: TransactionEntity) throws -> ConfirmedTransactionEntity {
|
||||
func enhance(transaction: TransactionEntity) async throws -> ConfirmedTransactionEntity {
|
||||
LoggerProxy.debug("Zoom.... Enhance... Tx: \(transaction.transactionId.toHexStringTxId())")
|
||||
|
||||
let transaction = try downloader.fetchTransaction(txId: transaction.transactionId)
|
||||
let transaction = try await downloader.fetchTransactionAsync(txId: transaction.transactionId)
|
||||
|
||||
let transactionID = transaction.transactionId.toHexStringTxId()
|
||||
let block = String(describing: transaction.minedHeight)
|
||||
|
@ -148,6 +156,16 @@ class CompactBlockEnhancementOperation: ZcashOperation {
|
|||
}
|
||||
return confirmedTx
|
||||
}
|
||||
|
||||
override func fail(error: Error? = nil) {
|
||||
self.cancelableTask?.cancel()
|
||||
super.fail(error: error)
|
||||
}
|
||||
|
||||
override func cancel() {
|
||||
self.cancelableTask?.cancel()
|
||||
super.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
private extension BlockRange {
|
||||
|
|
|
@ -125,6 +125,8 @@ class CompactBlockBatchScanningOperation: ZcashOperation {
|
|||
private var blockRange: CompactBlockRange
|
||||
private var transactionRepository: TransactionRepository
|
||||
private var network: NetworkType
|
||||
private var cancelableTask: Task<Void, Error>?
|
||||
private var done = false
|
||||
|
||||
private weak var progressDelegate: CompactBlockProgressDelegate?
|
||||
|
||||
|
@ -157,82 +159,94 @@ class CompactBlockBatchScanningOperation: ZcashOperation {
|
|||
|
||||
self.startedHandler?()
|
||||
|
||||
do {
|
||||
if batchSize == 0 {
|
||||
let scanStartTime = Date()
|
||||
guard self.rustBackend.scanBlocks(dbCache: self.cacheDb, dbData: self.dataDb, limit: batchSize, networkType: network) else {
|
||||
self.scanFailed(self.rustBackend.lastError() ?? ZcashOperationError.unknown)
|
||||
return
|
||||
}
|
||||
let scanFinishTime = Date()
|
||||
NotificationCenter.default.post(
|
||||
SDKMetrics.progressReportNotification(
|
||||
progress: BlockProgress(
|
||||
startHeight: self.blockRange.lowerBound,
|
||||
targetHeight: self.blockRange.upperBound,
|
||||
progressHeight: self.blockRange.upperBound
|
||||
),
|
||||
start: scanStartTime,
|
||||
end: scanFinishTime,
|
||||
task: .scanBlocks
|
||||
)
|
||||
)
|
||||
let seconds = scanFinishTime.timeIntervalSinceReferenceDate - scanStartTime.timeIntervalSinceReferenceDate
|
||||
LoggerProxy.debug("Scanned \(blockRange.count) blocks in \(seconds) seconds")
|
||||
} else {
|
||||
let scanStartHeight = try transactionRepository.lastScannedHeight()
|
||||
let targetScanHeight = blockRange.upperBound
|
||||
|
||||
var scannedNewBlocks = false
|
||||
var lastScannedHeight = scanStartHeight
|
||||
|
||||
repeat {
|
||||
guard !shouldCancel() else {
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
let previousScannedHeight = lastScannedHeight
|
||||
cancelableTask = Task {
|
||||
do {
|
||||
if batchSize == 0 {
|
||||
let scanStartTime = Date()
|
||||
guard self.rustBackend.scanBlocks(
|
||||
dbCache: self.cacheDb,
|
||||
dbData: self.dataDb,
|
||||
limit: batchSize,
|
||||
networkType: network
|
||||
) else {
|
||||
guard self.rustBackend.scanBlocks(dbCache: self.cacheDb, dbData: self.dataDb, limit: batchSize, networkType: network) else {
|
||||
self.scanFailed(self.rustBackend.lastError() ?? ZcashOperationError.unknown)
|
||||
return
|
||||
}
|
||||
let scanFinishTime = Date()
|
||||
|
||||
lastScannedHeight = try transactionRepository.lastScannedHeight()
|
||||
|
||||
scannedNewBlocks = previousScannedHeight != lastScannedHeight
|
||||
if scannedNewBlocks {
|
||||
let progress = BlockProgress(startHeight: scanStartHeight, targetHeight: targetScanHeight, progressHeight: lastScannedHeight)
|
||||
progressDelegate?.progressUpdated(.scan(progress))
|
||||
NotificationCenter.default.post(
|
||||
SDKMetrics.progressReportNotification(
|
||||
progress: progress,
|
||||
start: scanStartTime,
|
||||
end: scanFinishTime,
|
||||
task: .scanBlocks
|
||||
)
|
||||
NotificationCenter.default.post(
|
||||
SDKMetrics.progressReportNotification(
|
||||
progress: BlockProgress(
|
||||
startHeight: self.blockRange.lowerBound,
|
||||
targetHeight: self.blockRange.upperBound,
|
||||
progressHeight: self.blockRange.upperBound
|
||||
),
|
||||
start: scanStartTime,
|
||||
end: scanFinishTime,
|
||||
task: .scanBlocks
|
||||
)
|
||||
|
||||
let heightCount = lastScannedHeight - previousScannedHeight
|
||||
let seconds = scanFinishTime.timeIntervalSinceReferenceDate - scanStartTime.timeIntervalSinceReferenceDate
|
||||
LoggerProxy.debug("Scanned \(heightCount) blocks in \(seconds) seconds")
|
||||
}
|
||||
} while !self.isCancelled && scannedNewBlocks && lastScannedHeight < targetScanHeight
|
||||
)
|
||||
let seconds = scanFinishTime.timeIntervalSinceReferenceDate - scanStartTime.timeIntervalSinceReferenceDate
|
||||
LoggerProxy.debug("Scanned \(blockRange.count) blocks in \(seconds) seconds")
|
||||
} else {
|
||||
let scanStartHeight = try transactionRepository.lastScannedHeight()
|
||||
let targetScanHeight = blockRange.upperBound
|
||||
|
||||
var scannedNewBlocks = false
|
||||
var lastScannedHeight = scanStartHeight
|
||||
|
||||
repeat {
|
||||
guard !shouldCancel() else {
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
let previousScannedHeight = lastScannedHeight
|
||||
let scanStartTime = Date()
|
||||
guard self.rustBackend.scanBlocks(
|
||||
dbCache: self.cacheDb,
|
||||
dbData: self.dataDb,
|
||||
limit: batchSize,
|
||||
networkType: network
|
||||
) else {
|
||||
self.scanFailed(self.rustBackend.lastError() ?? ZcashOperationError.unknown)
|
||||
return
|
||||
}
|
||||
let scanFinishTime = Date()
|
||||
|
||||
lastScannedHeight = try transactionRepository.lastScannedHeight()
|
||||
|
||||
scannedNewBlocks = previousScannedHeight != lastScannedHeight
|
||||
if scannedNewBlocks {
|
||||
let progress = BlockProgress(startHeight: scanStartHeight, targetHeight: targetScanHeight, progressHeight: lastScannedHeight)
|
||||
progressDelegate?.progressUpdated(.scan(progress))
|
||||
NotificationCenter.default.post(
|
||||
SDKMetrics.progressReportNotification(
|
||||
progress: progress,
|
||||
start: scanStartTime,
|
||||
end: scanFinishTime,
|
||||
task: .scanBlocks
|
||||
)
|
||||
)
|
||||
|
||||
let heightCount = lastScannedHeight - previousScannedHeight
|
||||
let seconds = scanFinishTime.timeIntervalSinceReferenceDate - scanStartTime.timeIntervalSinceReferenceDate
|
||||
LoggerProxy.debug("Scanned \(heightCount) blocks in \(seconds) seconds")
|
||||
}
|
||||
} while !self.isCancelled && scannedNewBlocks && lastScannedHeight < targetScanHeight
|
||||
self.done = true
|
||||
}
|
||||
} catch {
|
||||
scanFailed(error)
|
||||
}
|
||||
} catch {
|
||||
scanFailed(error)
|
||||
}
|
||||
|
||||
while !done && !isCancelled {
|
||||
sleep(1)
|
||||
}
|
||||
}
|
||||
|
||||
func scanFailed(_ error: Error) {
|
||||
self.error = error
|
||||
self.cancelableTask?.cancel()
|
||||
LoggerProxy.debug("block scanning failed with error: \(String(describing: self.error))")
|
||||
self.fail()
|
||||
super.fail(error: error)
|
||||
}
|
||||
|
||||
override func cancel() {
|
||||
self.cancelableTask?.cancel()
|
||||
super.cancel()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,9 @@ class CompactBlockValidationOperation: ZcashOperation {
|
|||
private var cacheDb: URL
|
||||
private var dataDb: URL
|
||||
private var network: NetworkType
|
||||
|
||||
private var cancelableTask: Task<Void, Error>?
|
||||
private var done = false
|
||||
|
||||
init(
|
||||
rustWelding: ZcashRustBackendWelding.Type,
|
||||
cacheDb: URL,
|
||||
|
@ -44,23 +46,40 @@ class CompactBlockValidationOperation: ZcashOperation {
|
|||
|
||||
self.startedHandler?()
|
||||
|
||||
let result = self.rustBackend.validateCombinedChain(dbCache: cacheDb, dbData: dataDb, networkType: self.network)
|
||||
|
||||
switch result {
|
||||
case 0:
|
||||
let error = CompactBlockValidationError.failedWithError(rustBackend.lastError())
|
||||
self.error = error
|
||||
LoggerProxy.debug("block scanning failed with error: \(String(describing: self.error))")
|
||||
self.fail(error: error)
|
||||
cancelableTask = Task {
|
||||
let result = self.rustBackend.validateCombinedChain(dbCache: cacheDb, dbData: dataDb, networkType: self.network)
|
||||
|
||||
case ZcashRustBackendWeldingConstants.validChain:
|
||||
break
|
||||
|
||||
default:
|
||||
let error = CompactBlockValidationError.validationFailed(height: BlockHeight(result))
|
||||
self.error = error
|
||||
LoggerProxy.debug("block scanning failed with error: \(String(describing: self.error))")
|
||||
self.fail(error: error)
|
||||
switch result {
|
||||
case 0:
|
||||
let error = CompactBlockValidationError.failedWithError(rustBackend.lastError())
|
||||
self.error = error
|
||||
LoggerProxy.debug("block scanning failed with error: \(String(describing: self.error))")
|
||||
self.fail(error: error)
|
||||
|
||||
case ZcashRustBackendWeldingConstants.validChain:
|
||||
self.done = true
|
||||
break
|
||||
|
||||
default:
|
||||
let error = CompactBlockValidationError.validationFailed(height: BlockHeight(result))
|
||||
self.error = error
|
||||
LoggerProxy.debug("block scanning failed with error: \(String(describing: self.error))")
|
||||
self.fail(error: error)
|
||||
}
|
||||
}
|
||||
|
||||
while !done && !isCancelled {
|
||||
sleep(1)
|
||||
}
|
||||
}
|
||||
|
||||
override func fail(error: Error? = nil) {
|
||||
self.cancelableTask?.cancel()
|
||||
super.fail(error: error)
|
||||
}
|
||||
|
||||
override func cancel() {
|
||||
self.cancelableTask?.cancel()
|
||||
super.cancel()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,9 @@ class FetchUnspentTxOutputsOperation: ZcashOperation {
|
|||
private var startHeight: BlockHeight
|
||||
private var network: NetworkType
|
||||
private var dataDb: URL
|
||||
|
||||
private var cancelableTask: Task<Void, Error>?
|
||||
private var done = false
|
||||
|
||||
init(
|
||||
accountRepository: AccountRepository,
|
||||
downloader: CompactBlockDownloading,
|
||||
|
@ -49,30 +51,41 @@ class FetchUnspentTxOutputsOperation: ZcashOperation {
|
|||
|
||||
self.startedHandler?()
|
||||
|
||||
do {
|
||||
let tAddresses = try accountRepository.getAll().map({ $0.transparentAddress })
|
||||
cancelableTask = Task {
|
||||
do {
|
||||
for tAddress in tAddresses {
|
||||
guard try self.rustbackend.clearUtxos(
|
||||
dbData: dataDb,
|
||||
address: tAddress,
|
||||
sinceHeight: startHeight - 1,
|
||||
networkType: network
|
||||
) >= 0 else {
|
||||
throw rustbackend.lastError() ?? RustWeldingError.genericError(message: "attempted to clear utxos but -1 was returned")
|
||||
let tAddresses = try accountRepository.getAll().map({ $0.transparentAddress })
|
||||
do {
|
||||
for tAddress in tAddresses {
|
||||
guard try self.rustbackend.clearUtxos(
|
||||
dbData: dataDb,
|
||||
address: tAddress,
|
||||
sinceHeight: startHeight - 1,
|
||||
networkType: network
|
||||
) >= 0 else {
|
||||
throw rustbackend.lastError() ?? RustWeldingError.genericError(message: "attempted to clear utxos but -1 was returned")
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
throw FetchUTXOError.clearingFailed(error)
|
||||
}
|
||||
|
||||
var utxos: [UnspentTransactionOutputEntity] = []
|
||||
let stream: AsyncThrowingStream<UnspentTransactionOutputEntity, Error> = downloader.fetchUnspentTransactionOutputs(tAddresses: tAddresses, startHeight: startHeight)
|
||||
for try await transaction in stream {
|
||||
utxos.append(transaction)
|
||||
}
|
||||
|
||||
let result = storeUTXOs(utxos, in: dataDb)
|
||||
|
||||
self.fetchedUTXOsHandler?(result)
|
||||
self.done = true
|
||||
} catch {
|
||||
throw FetchUTXOError.clearingFailed(error)
|
||||
self.fail(error: error)
|
||||
}
|
||||
|
||||
let utxos = try downloader.fetchUnspentTransactionOutputs(tAddresses: tAddresses, startHeight: startHeight)
|
||||
|
||||
let result = storeUTXOs(utxos, in: dataDb)
|
||||
|
||||
self.fetchedUTXOsHandler?(result)
|
||||
} catch {
|
||||
self.fail(error: error)
|
||||
}
|
||||
|
||||
while !done && !isCancelled {
|
||||
sleep(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,4 +112,14 @@ class FetchUnspentTxOutputsOperation: ZcashOperation {
|
|||
|
||||
return (inserted: refreshed, skipped: skipped)
|
||||
}
|
||||
|
||||
override func fail(error: Error? = nil) {
|
||||
self.cancelableTask?.cancel()
|
||||
super.fail(error: error)
|
||||
}
|
||||
|
||||
override func cancel() {
|
||||
self.cancelableTask?.cancel()
|
||||
super.cancel()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,11 +28,9 @@ protocol CompactBlockRepository {
|
|||
/**
|
||||
Gets the highest block that is currently stored.
|
||||
Non-Blocking
|
||||
|
||||
- Parameter result: closure resulting on either the latest height or an error
|
||||
*/
|
||||
func latestHeight(result: @escaping (Result<BlockHeight, Error>) -> Void)
|
||||
|
||||
func latestHeightAsync() async throws -> BlockHeight
|
||||
|
||||
/**
|
||||
Write the given blocks to this store, which may be anything from an in-memory cache to a DB.
|
||||
Blocking
|
||||
|
@ -46,10 +44,9 @@ protocol CompactBlockRepository {
|
|||
Non-Blocking
|
||||
- Parameters:
|
||||
- Parameter blocks: array of blocks to be written to storage
|
||||
- Parameter completion: a closure that will be called after storing the blocks
|
||||
*/
|
||||
func write(blocks: [ZcashCompactBlock], completion: ((Error?) -> Void)?)
|
||||
|
||||
func writeAsync(blocks: [ZcashCompactBlock]) async throws
|
||||
|
||||
/**
|
||||
Remove every block above and including the given height.
|
||||
|
||||
|
@ -66,10 +63,7 @@ protocol CompactBlockRepository {
|
|||
After this operation, the data store will look the same as one that has not yet stored the given block height.
|
||||
Meaning, if max height is 100 block and rewindTo(50) is called, then the highest block remaining will be 49.
|
||||
|
||||
- Parameters:
|
||||
- Parameter height: the height to rewind to
|
||||
- Parameter completion: a closure that will be called after storing the blocks
|
||||
|
||||
*/
|
||||
func rewind(to height: BlockHeight, completion: ((Error?) -> Void)?)
|
||||
func rewindAsync(to height: BlockHeight) async throws
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"network": "main",
|
||||
"height": "1775000",
|
||||
"hash": "000000000019cdcd93e8a0704c40cd74e65424e4bfaaa2a21227db81355ccb46",
|
||||
"time": 1660646308,
|
||||
"saplingTree": "01597a94eed997b611665ea28eb0fbebf872dc4187b81baf2d7b061d9498e4be07001901289049f3d2fb297ec300241c8ca66400d8cb214272da11c7dddbf249a83b363200019448787f294385a1cf41c26b5ecc3a9f2b552d85dd959d71ad8fb79ab82f315e0000015692b62820a0affe568750d52d557ae99781acf19545f95404b3d7122e00e50d014c13e6f6cd1938716b4870921418d553fbc13ad5e174c720556e43eeedff992b01d5af984301be600c7cf840dc1fbbcdedb2d2e801813bb68a01be00c6822d5a6a017e978b347c274b38ee016285dd14132e83d59786019d1a46ce0163771dfdce0c000000017b24ec22b8e69bfebe3a24693645c8905f2c3756dd67d646d4266c5624ce29520001887d900f0f1c22d239b925d77200c12a7a637dfc7723f08aa34c0808cd1740200001e9358e668fd2780e13975fa8d46cd6ea762252a2ce849e2c82affb1c58edcb190000013eca32c92486829a47625ea4acb38897025abb7af0d1aba2d12c9e828a8d0a4f000000000139af7ec003ac4e37c263bab5642fcc4ec294a1e328ff025832eec45239041f6e",
|
||||
"orchardTree": "0182a273f144dba41ed805d348a8eeae5692b737863da75ac3384af983d54fd109001f01f72799b4c4c3ec3048b5c724b0edf553fdac716a6f2e771b8e40be6f9ece050301eec827aaef0952edafa106766d905c03b29a58b8f502b579e18d6b8a36b9a2120001997dd960a2474458cc8d914bf46232ec351eb5b3ff614e455d0fe6cf1c0d961f01726cc90e9a3d35324d807825bc4eceb7c976735bf8d5072f24f916f11231aa2901e4d4b64f108c937551964335b41b8a6e43bca7b2f2c468f86bb27a938ffb912001395fc86db243265b7a2722b3a49c1ac5449d671980bfaaebd1f8b26d4324451f0001056bee64e920ba6e8604fa32b294591abb40b5fc35b9b6f257b3b465fce371270001ea6a4ce4349b49c0b9788bcf94d27cb8c95f8f5a640919110387cd66f063e113017d6446e58ba6f7f8e7f60594b91bb67739986c89c670ad3996205ca9df7eac1100000001188cb8c8ad6ec4d5a9f90689123894bc1d021fb63d53347246ef21657c04f3110000014c58c6ffa8b0fdd89c604006318b7901020edcaca498e3afd81af7579dafcd340001f791f26a6ace2c09ba3deee8db26c3299e8e9ea6f4fdcac0846b2121721c310100000000000000000000"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"network": "main",
|
||||
"height": "1777500",
|
||||
"hash": "000000000114eb90f65670123d685d4e1ac4208dcc39a9dc1111060789a2c418",
|
||||
"time": 1660835117,
|
||||
"saplingTree": "0179c12f2782a76e421834ecfcd800a5cbd1edc79663d3c58d25d14200c60a2b050019000000000000000001091c24ca6d7180e15a22a46f9fa2d0a90783ce8e8bf4346097b36c469f7859220113d4335546307bb7558b2bfa8a309abb341da3f88acfc3b7d0523519a993662701d99f7f7123501008b4b145d772c66240aa9bdfe1fadd8cd420a3f159126950350185b933c8fc56ff06180fc5d2dbaf7234d615c724b1dbcdd4130ddff0ac732e6e000000019fe9488e3027bf007c951a3706ac7422d242c3ece25c20d5fd8254fdc77d883c000177ac81d2104e4de33629aaf3187c8daff10899ef791b1fbb18d2f2c17296870a0000018679bff98f1311c6b1c4df01647556064d2cd34087c8f83fac1ee99babc986600000000139af7ec003ac4e37c263bab5642fcc4ec294a1e328ff025832eec45239041f6e",
|
||||
"orchardTree": "01dde5b2585ed32435eba299a594f328983090c620d3e40c58e2c457c5adbc7835001f01430c6ec1ba7a552b02f897a8789639760786e29fc4ce7e133f4d8768fba4032b0001b99142688612333a2926ebf2b271c50018a4240c9522cdee66b68c4ffa8c3616000172a6fbb0176b644a4a11f6c658324fc5d8140845959cb3c924b190a8ef86e22a0153250a8de904795ee993882737ee5f13458561a0f78d6ab1432e165f0b19ed2f01b54e695a6d674420b22d8b52727140dbde2d83ed45966a2cde91393d89ea6a0101d3f0b23da54e9066a2e4621baa67d255a69f90f788e35975e5fc14ae62eb9b3d012d59e25ff1850760f04238d20341db41c77a069ce6146af0c66693c5a7e84c04014caf0366131977fe12e0ef793ad22fa3f75df7a2bca71acba67bbb206797ff3c0001ce3e5c7e4f546304954681fd0e8f0e68dc38e5c788c99c1cc2a5404c160df93a0001038ca3c0ad85cbc76b94531a2c8d7efc43af084abdc88d2d28b30bc3a8ba4d39000001aa7b1980e5656743063400012808a5a2920431959e0b721c9a915b37ca3b450801c4accd50986a74b77eddf2e5191d20e40035f38bc7c9b91a03339af16c5a7032014c58c6ffa8b0fdd89c604006318b7901020edcaca498e3afd81af7579dafcd340001f791f26a6ace2c09ba3deee8db26c3299e8e9ea6f4fdcac0846b2121721c310100000000000000000000"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"network": "main",
|
||||
"height": "1780000",
|
||||
"hash": "000000000092cd2f7d70451422ec93bc0c32dbb4b7ba7bfab4c6bb2f646621cf",
|
||||
"time": 1661023245,
|
||||
"saplingTree": "01eb57dc27bf63678d8d3a9d19b422a4694a9d43765bd308abd6ac1ee838dc4524018572cb62805c814962aee358456f07f5494cf3fa7b9ec1bc35dcd8f217e0920b19014241b45704d5126780eede03872b8f87501e4184dc68f977aab8e20d1e83da330001be1052772495777a8224029288e3cbce5f6528380c7dfab653661fa068e43267000000000120d655140e8a7069e4bb227ef3be10337d1fe805f6c143042f39e04047dcaa4801edee36cd129d61db744d5c70d749a066ae0903b5310f309609d014d349b7e435000001e4730f055d123a824efda2abf609b64bca407df2582fb188f15876c17a93183f01428fe4cdc82c312139518ae3cfed4fc769329bc192c724029a38dbf221557a56000176138376dab12f9063c0d4be21178499d1f912756be2dda3cb7540469376905901b261f10e8b41673b7707c93d6a38c9b3ca331d7beaf312b17dc5536bf9ac262500018fc9b4ef24688bf42b782c41232f9ec501b1c4ab6c950b0c41d34eb23b17402800017412114010d9ffb2f7387eda6e29942c0c80b6330788102467e4a0afe325382d018679bff98f1311c6b1c4df01647556064d2cd34087c8f83fac1ee99babc986600000000139af7ec003ac4e37c263bab5642fcc4ec294a1e328ff025832eec45239041f6e",
|
||||
"orchardTree": "01b02222e4afcd845dc497c76d04b9f6ddb9081d01b9f9d5a2aa05fbc8d1443b1601a0331c1517205b7e943e9668d61e77e875c662dc96ef7cc96299b6a83890b41d1f0000013c6b5a330ccb2ba9442273535baa2dc7fa6dbf999b72b31afe032c168f4bd7080001e74ec029cd1c152dc8b09f65985d6c0c2c78e56da80c941538520a28587d9f160181a58cf9d3ea78a5685698258689ebe5fa4ce66d0ef9eceb6ae478750ef63139012e734c4d341726e1c02519bca7c04706db73fede3e95e9eb81208265d7b5c51e01e12417482428167d1173531eb01c4f05257c8915bd7b3c81668f7e4c0525d91901673db13a5adedf791c6b644470c5f61d202abec03de1ad93ad9b534e93925e0c01256c8aa3be887192ee742261edd0c2788d1b625442150145f4d3b8ed4905c218017fcf9eb3250652f2d0edd5af7d812909570a857529d71182f1e67fe20131b43a01c11b33655a2af90f359b1372d26da8e92bd8885107b6cc623e96243d56ec051700010d01fcaf34b9d9127ad8aade1bc05ed6c70040a7146a9fd596073bfcea1aad390137638774e0047f7be64682876e9fa29021fb428b367731ff1dc7701b58633e390000000001081565fb9592a4fab10edbfb15d2aa45c89eb85837f4f298c586cb21d45b772901f791f26a6ace2c09ba3deee8db26c3299e8e9ea6f4fdcac0846b2121721c310100000000000000000000"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"network": "main",
|
||||
"height": "1782500",
|
||||
"hash": "0000000000c96f27e270aa37db650cf15c6b75f1fa59a947cca4f41abf004676",
|
||||
"time": 1661211894,
|
||||
"saplingTree": "01ed3ce95d71c92565819babefc0f1026beac767dd6a162ac0ae9b15f619446545001900000001ac44d394a0bac1701dd6b74ab80f53729963826696a1da89aae59e12cf4c1b5f01dacf1de9631ba5147d124a2502808ee3eabdccbcaee03b03521cf765324f52710001efe591a8f59c1b2271ff973d8204c588b21747c305a7603cac7476f62424ed0d000000000138279c0da3d1576d92933860f5de697d212036da77df1af780bebe1b0fb1df2700000001734a94d73f408cf9aa047cb69f2b67382cd2eac7ad9fd8d4dca6b9ef4706d93a01323df8cc8affced4411de770643c86329441d276e3d0af469a5387baf14b702e000196ea06c6c9b1bffd35111b29addc63a564d780556def4814bd2bdf44568add0000000190fd9fe569252b58449910aeb7a9d5bed775699b04b2b0d2373b948728ce291b00000139af7ec003ac4e37c263bab5642fcc4ec294a1e328ff025832eec45239041f6e",
|
||||
"orchardTree": "0173e8d2617537311c62aa77f610f752e4553fac6d8f8cdb05248941a2afc25f0b001f00011093e632be4376c29ca004fa22ceeb426c283d9006436eba5185b63ec4adab09000001ed13450a8b52b2467727d09d721f8054d408cc007a3574f090bca255d94da90800012d81bec0d20bb2214b91f3caf8d03c66c779b67f06a9908bfb239e25b2156c1400019971eb95fe89873ce0271ed1e70b8ea4498e54a81d4db7b092fefc7b9f540212000146181485362325772638425fe945f012e9b3884886dfc0f5c689f556d40d8032000001cbc56207feb2d10de3c2dffcc93040d4ed95a1d0c653c9587739681a162a601401aad0d336606800990785d124bdfe61ffbd399167bbc344f5855d3d4de468de190001464e545a0f5a15e6c09f82335c092a66ff8f10d0abe8dd0db230ca90dbcc0d2401f11d7f967046007bf41c33b30c0dc3b52c1a4a9cc3a7a85657a2fc11a39d393a0001081565fb9592a4fab10edbfb15d2aa45c89eb85837f4f298c586cb21d45b772901f791f26a6ace2c09ba3deee8db26c3299e8e9ea6f4fdcac0846b2121721c310100000000000000000000"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"network": "main",
|
||||
"height": "1785000",
|
||||
"hash": "000000000048a2a2cc1132d171fd58ae0483322d33a4ca4e5814d2f928358ddb",
|
||||
"time": 1661400251,
|
||||
"saplingTree": "019cdc2862d4223e86a3b2780f9cdf19b2b22431faa4c849d39f681bd01d32a0630145fdfaf100b993c09d16b34c6bb30834fbd9519be36b7cf5adc645fd2727805a190196199419320b54a8acf9a9b6883abf64a7e80fe75a17a6227bd47b8a2636b84700000001c5c6f40ccdd6c8c7c8b8257c1dbed8c9ab5b99320c0b367bd80c471f676dfe3d01324e46f8529d6becc636a9b57eb864b3cc6a19f9e1cf3da6fcd4b96456fdf1350111fe0737c21b236b783ca356947277888a785e569d1c8953d341741df944742800010e4303d3df4670374eec9b5fff8b9b7cead7c3720ccfc57bc05e9f15e005420a019a74161a408604546f401b8616c50dcd38a10efca83d1a5f0bc87f43ba3359670187130c30b7023f7d9a80fe75fcc1c7864007ae29e63c9a85dff0cc60e9055f5201d7a644ef58eeed93ab36be7ef27d90dbe43696ce2c0c2d1969e3de9f1cc9e51c013dc034d5b0eff46aa39a5461cdc285a75705eadf417e14fcb6a07feb4ed3a0530001f3a3cab7e488e34450427f914284cff92aca699a2e3bee42c42212419bb72a00000001c9c6bba2bb2a19be1e993af5f9bc35979454afa6237a44ad46ed0cd06c7eca4901e1a9472dadbe9da7956818483b066069ad0030dee06a787200e5519a5e0b96600001757bfb5957a0fa9b4fc9e8c105df1e9f0f9e156d653ba54a5fd2ebaa237afa510190fd9fe569252b58449910aeb7a9d5bed775699b04b2b0d2373b948728ce291b00000139af7ec003ac4e37c263bab5642fcc4ec294a1e328ff025832eec45239041f6e",
|
||||
"orchardTree": "01fcefe6872d4fa4b8bf4cde106616dd137593b43fd761478eb4d1dd6715a4cc21001f0000000118ef33685241afb399b6d9c0697404998528096ae550dcd75365912cfb64953100019ccc0dc23d60dddcadb86ecabcfe1e5d42829a741f7e6705a368ead59ac492260158cda00196a2f05b86d770724944d4db0ff55d7442962dec634e3968822df01b019f815362606a86082ca9c3a332d4fbea2faef7c6be9cf4f248fa09672ab6012301ce1619c190c7fb2f62560a1723b9daf6ab97d03406bc4537ef4da5dbe4ea993e0000000001cbd9a766f5802ce880a9741919503a6b5b2e58104d1331b7c477d758aad8fe1400018ea310e6e8006b04172395acba6ef11cbef90cf053489a7f8b3287be3935ed3d0000019886882316b2f5a810dda1ece4d983ed360175e2cc5ed2b3781ee1d9f1e05f2801081565fb9592a4fab10edbfb15d2aa45c89eb85837f4f298c586cb21d45b772901f791f26a6ace2c09ba3deee8db26c3299e8e9ea6f4fdcac0846b2121721c310100000000000000000000"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"network": "test",
|
||||
"height": "2000000",
|
||||
"hash": "000bb3c6d575a155a56b1aab0e7f14a1141d25c1f36aa6f15c1cb1ef1d7d498c",
|
||||
"time": 1660621966,
|
||||
"saplingTree": "0133914238639e4f22ddc8ca2cab7e2d7ec676b06f12a0bf42bc757909cec4f47200100103217f60b7d9bdc625ecd5d6170e3ab57a81eb29f7beacecd07c4f3f0d61ef2801066673d6ab6b62a91f6e04a49fc0e74083cfcccdc851db681e01db333ee1cb470000018da55ded8e55006c2a6c41474da220a9a179a85a99a48df0a31a74291317720e00012233753a4db3b97f44b3bb4d77034fd77c8e5c7938092724cb4a3bf3491bc1180160a5822bf1407657b82e959214634ec4c36a092bc1ab7615286058d8bc06152c01d878f6e29835fd77030d6c7395e85231d74c3a4d72659c8f301d65dfc2f3c51f018bd9ca6b4e00aac24d384b8d85b32481e0b4335ab3de5a0dea5c61aa32366153019aa3b71d9ce27ab88add19fda2e50caf313de20a04c6b72f5fbe1783980431730122c55fdffb446e39b73f1606907b2889d18b01ac818a0cbd4b2c661ad6a5a170000117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39",
|
||||
"orchardTree": "01a682706317caa5aec999385ac580445ff4eff6347e4a3c844ac18fcb5fe9bf1c01cca6f37237f27037fa7f8fe5ec8d2cc251b791cfb9cdd08cd1215229fa9435221f0001590d3e7e3f4cd572274f79f4a95b41fa72ed9b42a7c6dbcaec9637eaf368ac0e0000018843337920418307fa7699d506bb0f47a79aea7f6fe8efc1e25b9dde8966e22f013b5a8ef020d8b30fa8beb8406dd30b2a1944755f5549713e4fe24de78ab72e12000001a46523754a6d3fbc3226d6221dafca357d930e183297a0ba1cfa2db5d0500e1f01b6fd291e9d6068bc24e99aefe49f8f29836ed1223deabc23871f1a1288f9240300016fc552915a0d5bc5c0c0cdf29453edf081d9a2de396535e6084770c38dcff838019518d88883e466a41ca67d6b986739fb2f601d77bb957398ed899de70b2a9f0801cd4871c1f545e7f5d844cc65fb00b8a162e316c3d1a435b00c435032b732c4280000000000000000000000000000000000"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"network": "test",
|
||||
"height": "2010000",
|
||||
"hash": "0013159a578c874aeecddad8707b8e274a018078fd80fc3b9e2d04065abeb05d",
|
||||
"time": 1661274815,
|
||||
"saplingTree": "012bd51ef4da530bb488d43a0f770109df7186ef164a64f618038bb00b7861840a00100001d3a6dfc2fac7c968ce7f96efdddc9764bc320230d8ce166637f8b73b6453e8670000000197e98f0a36d7a5ccac4b4ec963223a4eaab38188eb2a658ff01da4880839996e012233753a4db3b97f44b3bb4d77034fd77c8e5c7938092724cb4a3bf3491bc1180160a5822bf1407657b82e959214634ec4c36a092bc1ab7615286058d8bc06152c01d878f6e29835fd77030d6c7395e85231d74c3a4d72659c8f301d65dfc2f3c51f018bd9ca6b4e00aac24d384b8d85b32481e0b4335ab3de5a0dea5c61aa32366153019aa3b71d9ce27ab88add19fda2e50caf313de20a04c6b72f5fbe1783980431730122c55fdffb446e39b73f1606907b2889d18b01ac818a0cbd4b2c661ad6a5a170000117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39",
|
||||
"orchardTree": "014b0ab9afb38a6c819d64806b3de5397c6469ca0f7e58274f5c779ecb75d94217018646890daed861a8f66a3966e884da1b1c8240bb47327a348fae9169eb8205051f000118681f82320257f5a5cfc5c846fd4e88641d4ed7b87fcd5ec8e65e68e3ab0636000155cd8735904f69800ba500bf8af6fc70bfb2abb3d7ca1c75a1cce183b763f30400016e57cbad21bab804109f19479a88046b5c7f8da0d21e8217ac467801235c52200001a8773a2b01e9efd1011ea7d8d1071ad0a01c6c73e2fb6df802e307df17b4ac0601a46523754a6d3fbc3226d6221dafca357d930e183297a0ba1cfa2db5d0500e1f01b6fd291e9d6068bc24e99aefe49f8f29836ed1223deabc23871f1a1288f9240300016fc552915a0d5bc5c0c0cdf29453edf081d9a2de396535e6084770c38dcff838019518d88883e466a41ca67d6b986739fb2f601d77bb957398ed899de70b2a9f0801cd4871c1f545e7f5d844cc65fb00b8a162e316c3d1a435b00c435032b732c4280000000000000000000000000000000000"
|
||||
}
|
|
@ -90,7 +90,8 @@ public extension BlockProgress {
|
|||
public class LightWalletGRPCService {
|
||||
let channel: Channel
|
||||
let connectionManager: ConnectionStatusManager
|
||||
let compactTxStreamer: CompactTxStreamerClient
|
||||
let compactTxStreamer: CompactTxStreamerNIOClient
|
||||
let compactTxStreamerAsync: CompactTxStreamerAsyncClient
|
||||
let singleCallTimeout: TimeLimit
|
||||
let streamingCallTimeout: TimeLimit
|
||||
|
||||
|
@ -135,7 +136,14 @@ public class LightWalletGRPCService {
|
|||
|
||||
self.channel = channel
|
||||
|
||||
compactTxStreamer = CompactTxStreamerClient(
|
||||
compactTxStreamer = CompactTxStreamerNIOClient(
|
||||
channel: self.channel,
|
||||
defaultCallOptions: Self.callOptions(
|
||||
timeLimit: self.singleCallTimeout
|
||||
)
|
||||
)
|
||||
|
||||
compactTxStreamerAsync = CompactTxStreamerAsyncClient(
|
||||
channel: self.channel,
|
||||
defaultCallOptions: Self.callOptions(
|
||||
timeLimit: self.singleCallTimeout
|
||||
|
@ -146,6 +154,7 @@ public class LightWalletGRPCService {
|
|||
deinit {
|
||||
_ = channel.close()
|
||||
_ = compactTxStreamer.channel.close()
|
||||
_ = compactTxStreamerAsync.channel.close()
|
||||
}
|
||||
|
||||
func stop() {
|
||||
|
@ -155,7 +164,7 @@ public class LightWalletGRPCService {
|
|||
func blockRange(startHeight: BlockHeight, endHeight: BlockHeight? = nil, result: @escaping (CompactBlock) -> Void) throws -> ServerStreamingCall<BlockRange, CompactBlock> {
|
||||
compactTxStreamer.getBlockRange(BlockRange(startHeight: startHeight, endHeight: endHeight), handler: result)
|
||||
}
|
||||
|
||||
|
||||
func latestBlock() throws -> BlockID {
|
||||
try compactTxStreamer.getLatestBlock(ChainSpec()).response.wait()
|
||||
}
|
||||
|
@ -179,122 +188,18 @@ public class LightWalletGRPCService {
|
|||
}
|
||||
}
|
||||
|
||||
extension LightWalletGRPCService: LightWalletService {
|
||||
@discardableResult
|
||||
public func blockStream(
|
||||
startHeight: BlockHeight,
|
||||
endHeight: BlockHeight,
|
||||
result: @escaping (Result<GRPCResult, LightWalletServiceError>) -> Void,
|
||||
handler: @escaping (ZcashCompactBlock) -> Void,
|
||||
progress: @escaping (BlockProgress) -> Void
|
||||
) -> CancellableCall {
|
||||
let future = compactTxStreamer.getBlockRange(
|
||||
BlockRange(
|
||||
startHeight: startHeight,
|
||||
endHeight: endHeight
|
||||
),
|
||||
callOptions: Self.callOptions(timeLimit: self.streamingCallTimeout),
|
||||
handler: { compactBlock in
|
||||
handler(ZcashCompactBlock(compactBlock: compactBlock))
|
||||
progress(
|
||||
BlockProgress(
|
||||
startHeight: startHeight,
|
||||
targetHeight: endHeight,
|
||||
progressHeight: BlockHeight(compactBlock.height)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
future.status.whenComplete { completionResult in
|
||||
switch completionResult {
|
||||
case .success(let status):
|
||||
switch status.code {
|
||||
case .ok:
|
||||
result(.success(GRPCResult.success))
|
||||
default:
|
||||
result(.failure(LightWalletServiceError.mapCode(status)))
|
||||
}
|
||||
case .failure(let error):
|
||||
result(.failure(LightWalletServiceError.genericError(error: error)))
|
||||
}
|
||||
}
|
||||
return future
|
||||
}
|
||||
|
||||
// MARK: - LightWalletServiceBlockingAPI
|
||||
|
||||
extension LightWalletGRPCService: LightWalletServiceBlockingAPI {
|
||||
public func getInfo() throws -> LightWalletdInfo {
|
||||
try compactTxStreamer.getLightdInfo(Empty()).response.wait()
|
||||
}
|
||||
|
||||
public func getInfo(result: @escaping (Result<LightWalletdInfo, LightWalletServiceError>) -> Void) {
|
||||
compactTxStreamer.getLightdInfo(Empty()).response.whenComplete { completionResult in
|
||||
switch completionResult {
|
||||
case .success(let info):
|
||||
result(.success(info))
|
||||
case .failure(let error):
|
||||
result(.failure(error.mapToServiceError()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func closeConnection() {
|
||||
_ = channel.close()
|
||||
}
|
||||
|
||||
public func fetchTransaction(txId: Data) throws -> TransactionEntity {
|
||||
var txFilter = TxFilter()
|
||||
txFilter.hash = txId
|
||||
|
||||
do {
|
||||
let rawTx = try compactTxStreamer.getTransaction(txFilter).response.wait()
|
||||
|
||||
return TransactionBuilder.createTransactionEntity(txId: txId, rawTransaction: rawTx)
|
||||
} catch {
|
||||
throw error.mapToServiceError()
|
||||
}
|
||||
}
|
||||
|
||||
public func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
|
||||
var txFilter = TxFilter()
|
||||
txFilter.hash = txId
|
||||
|
||||
compactTxStreamer.getTransaction(txFilter).response.whenComplete { response in
|
||||
switch response {
|
||||
case .failure(let error):
|
||||
result(.failure(error.mapToServiceError()))
|
||||
case .success(let rawTx):
|
||||
result(.success(TransactionBuilder.createTransactionEntity(txId: txId, rawTransaction: rawTx)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func submit(spendTransaction: Data, result: @escaping (Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
|
||||
do {
|
||||
let transaction = try RawTransaction(serializedData: spendTransaction)
|
||||
let response = self.compactTxStreamer.sendTransaction(transaction).response
|
||||
|
||||
response.whenComplete { responseResult in
|
||||
switch responseResult {
|
||||
case .failure(let error):
|
||||
result(.failure(LightWalletServiceError.sentFailed(error: error)))
|
||||
case .success(let success):
|
||||
result(.success(success))
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
result(.failure(error.mapToServiceError()))
|
||||
}
|
||||
}
|
||||
|
||||
public func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
|
||||
let rawTx = RawTransaction.with { raw in
|
||||
raw.data = spendTransaction
|
||||
}
|
||||
do {
|
||||
return try compactTxStreamer.sendTransaction(rawTx).response.wait()
|
||||
} catch {
|
||||
throw error.mapToServiceError()
|
||||
public func latestBlockHeight() throws -> BlockHeight {
|
||||
guard let height = try? compactTxStreamer.getLatestBlock(ChainSpec()).response.wait().compactBlockHeight() else {
|
||||
throw LightWalletServiceError.timeOut
|
||||
}
|
||||
return height
|
||||
}
|
||||
|
||||
public func blockRange(_ range: CompactBlockRange) throws -> [ZcashCompactBlock] {
|
||||
|
@ -315,51 +220,30 @@ extension LightWalletGRPCService: LightWalletService {
|
|||
}
|
||||
}
|
||||
|
||||
public func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void) {
|
||||
let response = compactTxStreamer.getLatestBlock(ChainSpec()).response
|
||||
|
||||
response.whenSuccessBlocking(onto: queue) { blockID in
|
||||
guard let blockHeight = Int(exactly: blockID.height) else {
|
||||
result(.failure(LightWalletServiceError.generalError(message: "error creating blockheight from BlockID \(blockID)")))
|
||||
return
|
||||
}
|
||||
result(.success(blockHeight))
|
||||
public func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
|
||||
let rawTx = RawTransaction.with { raw in
|
||||
raw.data = spendTransaction
|
||||
}
|
||||
|
||||
response.whenFailureBlocking(onto: queue) { error in
|
||||
result(.failure(error.mapToServiceError()))
|
||||
do {
|
||||
return try compactTxStreamer.sendTransaction(rawTx).response.wait()
|
||||
} catch {
|
||||
throw error.mapToServiceError()
|
||||
}
|
||||
}
|
||||
|
||||
public func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void) {
|
||||
queue.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
var blocks: [CompactBlock] = []
|
||||
let response = self.compactTxStreamer.getBlockRange(range.blockRange(), handler: { blocks.append($0) })
|
||||
|
||||
do {
|
||||
let status = try response.status.wait()
|
||||
switch status.code {
|
||||
case .ok:
|
||||
result(.success(blocks.asZcashCompactBlocks()))
|
||||
|
||||
default:
|
||||
result(.failure(.mapCode(status)))
|
||||
}
|
||||
} catch {
|
||||
result(.failure(error.mapToServiceError()))
|
||||
}
|
||||
public func fetchTransaction(txId: Data) throws -> TransactionEntity {
|
||||
var txFilter = TxFilter()
|
||||
txFilter.hash = txId
|
||||
|
||||
do {
|
||||
let rawTx = try compactTxStreamer.getTransaction(txFilter).response.wait()
|
||||
|
||||
return TransactionBuilder.createTransactionEntity(txId: txId, rawTransaction: rawTx)
|
||||
} catch {
|
||||
throw error.mapToServiceError()
|
||||
}
|
||||
}
|
||||
|
||||
public func latestBlockHeight() throws -> BlockHeight {
|
||||
guard let height = try? latestBlock().compactBlockHeight() else {
|
||||
throw LightWalletServiceError.timeOut
|
||||
}
|
||||
return height
|
||||
}
|
||||
|
||||
public func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
||||
let arg = GetAddressUtxosArg.with { utxoArgs in
|
||||
utxoArgs.addresses = [tAddress]
|
||||
|
@ -383,7 +267,168 @@ extension LightWalletGRPCService: LightWalletService {
|
|||
}
|
||||
}
|
||||
|
||||
public func fetchUTXOs(for tAddress: String, height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) {
|
||||
public func fetchUTXOs(for tAddresses: [String], height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
||||
guard !tAddresses.isEmpty else {
|
||||
return [] // FIXME: throw a real error
|
||||
}
|
||||
|
||||
var utxos: [UnspentTransactionOutputEntity] = []
|
||||
|
||||
let arg = GetAddressUtxosArg.with { utxoArgs in
|
||||
utxoArgs.addresses = tAddresses
|
||||
utxoArgs.startHeight = UInt64(height)
|
||||
}
|
||||
utxos.append(
|
||||
contentsOf:
|
||||
try self.compactTxStreamer.getAddressUtxos(arg).response.wait().addressUtxos.map { reply in
|
||||
UTXO(
|
||||
id: nil,
|
||||
address: reply.address,
|
||||
prevoutTxId: reply.txid,
|
||||
prevoutIndex: Int(reply.index),
|
||||
script: reply.script,
|
||||
valueZat: Int(reply.valueZat),
|
||||
height: Int(reply.height),
|
||||
spentInTx: nil
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
return utxos
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - LightWalletServiceNonBlockingAPI
|
||||
|
||||
extension LightWalletGRPCService: LightWalletServiceNonBlockingAPI {
|
||||
public func getInfo(result: @escaping (Result<LightWalletdInfo, LightWalletServiceError>) -> Void) {
|
||||
compactTxStreamer.getLightdInfo(Empty()).response.whenComplete { completionResult in
|
||||
switch completionResult {
|
||||
case .success(let info):
|
||||
result(.success(info))
|
||||
case .failure(let error):
|
||||
result(.failure(error.mapToServiceError()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func getInfoAsync() async throws -> LightWalletdInfo {
|
||||
try await compactTxStreamerAsync.getLightdInfo(Empty())
|
||||
}
|
||||
|
||||
public func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void) {
|
||||
let response = compactTxStreamer.getLatestBlock(ChainSpec()).response
|
||||
|
||||
response.whenSuccessBlocking(onto: queue) { blockID in
|
||||
guard let blockHeight = Int(exactly: blockID.height) else {
|
||||
result(.failure(LightWalletServiceError.generalError(message: "error creating blockheight from BlockID \(blockID)")))
|
||||
return
|
||||
}
|
||||
result(.success(blockHeight))
|
||||
}
|
||||
|
||||
response.whenFailureBlocking(onto: queue) { error in
|
||||
result(.failure(error.mapToServiceError()))
|
||||
}
|
||||
}
|
||||
|
||||
public func latestBlockHeightAsync() async throws -> BlockHeight {
|
||||
try await BlockHeight(compactTxStreamerAsync.getLatestBlock(ChainSpec()).height)
|
||||
}
|
||||
|
||||
public func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void) {
|
||||
queue.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
var blocks: [CompactBlock] = []
|
||||
let response = self.compactTxStreamer.getBlockRange(range.blockRange(), handler: { blocks.append($0) })
|
||||
|
||||
do {
|
||||
let status = try response.status.wait()
|
||||
switch status.code {
|
||||
case .ok:
|
||||
result(.success(blocks.asZcashCompactBlocks()))
|
||||
|
||||
default:
|
||||
result(.failure(.mapCode(status)))
|
||||
}
|
||||
} catch {
|
||||
result(.failure(error.mapToServiceError()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func blockRange(_ range: CompactBlockRange) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
||||
let stream = compactTxStreamerAsync.getBlockRange(range.blockRange())
|
||||
|
||||
return AsyncThrowingStream { continuation in
|
||||
Task {
|
||||
do {
|
||||
for try await block in stream {
|
||||
continuation.yield(ZcashCompactBlock(compactBlock: block))
|
||||
}
|
||||
continuation.finish(throwing: nil)
|
||||
} catch {
|
||||
continuation.finish(throwing: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func submit(spendTransaction: Data, result: @escaping (Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
|
||||
do {
|
||||
let transaction = try RawTransaction(serializedData: spendTransaction)
|
||||
let response = self.compactTxStreamer.sendTransaction(transaction).response
|
||||
|
||||
response.whenComplete { responseResult in
|
||||
switch responseResult {
|
||||
case .failure(let error):
|
||||
result(.failure(LightWalletServiceError.sentFailed(error: error)))
|
||||
case .success(let success):
|
||||
result(.success(success))
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
result(.failure(error.mapToServiceError()))
|
||||
}
|
||||
}
|
||||
|
||||
public func submitAsync(spendTransaction: Data) async throws -> LightWalletServiceResponse {
|
||||
do {
|
||||
let transaction = try RawTransaction(serializedData: spendTransaction)
|
||||
return try await compactTxStreamerAsync.sendTransaction(transaction)
|
||||
} catch {
|
||||
throw LightWalletServiceError.sentFailed(error: error)
|
||||
}
|
||||
}
|
||||
|
||||
public func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
|
||||
var txFilter = TxFilter()
|
||||
txFilter.hash = txId
|
||||
|
||||
compactTxStreamer.getTransaction(txFilter).response.whenComplete { response in
|
||||
switch response {
|
||||
case .failure(let error):
|
||||
result(.failure(error.mapToServiceError()))
|
||||
case .success(let rawTx):
|
||||
result(.success(TransactionBuilder.createTransactionEntity(txId: txId, rawTransaction: rawTx)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func fetchTransactionAsync(txId: Data) async throws -> TransactionEntity {
|
||||
var txFilter = TxFilter()
|
||||
txFilter.hash = txId
|
||||
|
||||
let rawTx = try await compactTxStreamerAsync.getTransaction(txFilter)
|
||||
return TransactionBuilder.createTransactionEntity(txId: txId, rawTransaction: rawTx)
|
||||
}
|
||||
|
||||
public func fetchUTXOs(
|
||||
for tAddress: String,
|
||||
height: BlockHeight,
|
||||
result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>
|
||||
) -> Void) {
|
||||
queue.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
let arg = GetAddressUtxosArg.with { utxoArgs in
|
||||
|
@ -420,36 +465,13 @@ extension LightWalletGRPCService: LightWalletService {
|
|||
}
|
||||
}
|
||||
|
||||
public func fetchUTXOs(for tAddresses: [String], height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
||||
guard !tAddresses.isEmpty else {
|
||||
return [] // FIXME: throw a real error
|
||||
}
|
||||
|
||||
var utxos: [UnspentTransactionOutputEntity] = []
|
||||
|
||||
let arg = GetAddressUtxosArg.with { utxoArgs in
|
||||
utxoArgs.addresses = tAddresses
|
||||
utxoArgs.startHeight = UInt64(height)
|
||||
}
|
||||
utxos.append(
|
||||
contentsOf:
|
||||
try self.compactTxStreamer.getAddressUtxos(arg).response.wait().addressUtxos.map { reply in
|
||||
UTXO(
|
||||
id: nil,
|
||||
address: reply.address,
|
||||
prevoutTxId: reply.txid,
|
||||
prevoutIndex: Int(reply.index),
|
||||
script: reply.script,
|
||||
valueZat: Int(reply.valueZat),
|
||||
height: Int(reply.height),
|
||||
spentInTx: nil
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
return utxos
|
||||
public func fetchUTXOs(
|
||||
for tAddress: String,
|
||||
height: BlockHeight
|
||||
) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
||||
return fetchUTXOs(for: [tAddress], height: height)
|
||||
}
|
||||
|
||||
|
||||
public func fetchUTXOs(
|
||||
for tAddresses: [String],
|
||||
height: BlockHeight,
|
||||
|
@ -495,6 +517,119 @@ extension LightWalletGRPCService: LightWalletService {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func fetchUTXOs(
|
||||
for tAddresses: [String],
|
||||
height: BlockHeight
|
||||
) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
||||
guard !tAddresses.isEmpty else {
|
||||
return AsyncThrowingStream { _ in }
|
||||
}
|
||||
|
||||
let args = GetAddressUtxosArg.with { utxoArgs in
|
||||
utxoArgs.addresses = tAddresses
|
||||
utxoArgs.startHeight = UInt64(height)
|
||||
}
|
||||
let stream = compactTxStreamerAsync.getAddressUtxosStream(args)
|
||||
|
||||
return AsyncThrowingStream { continuation in
|
||||
Task {
|
||||
do {
|
||||
for try await reply in stream {
|
||||
continuation.yield(
|
||||
UTXO(
|
||||
id: nil,
|
||||
address: reply.address,
|
||||
prevoutTxId: reply.txid,
|
||||
prevoutIndex: Int(reply.index),
|
||||
script: reply.script,
|
||||
valueZat: Int(reply.valueZat),
|
||||
height: Int(reply.height),
|
||||
spentInTx: nil
|
||||
)
|
||||
)
|
||||
}
|
||||
continuation.finish(throwing: nil)
|
||||
} catch {
|
||||
continuation.finish(throwing: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public func blockStream(
|
||||
startHeight: BlockHeight,
|
||||
endHeight: BlockHeight,
|
||||
result: @escaping (Result<GRPCResult, LightWalletServiceError>) -> Void,
|
||||
handler: @escaping (ZcashCompactBlock) -> Void,
|
||||
progress: @escaping (BlockProgress) -> Void
|
||||
) -> CancellableCall {
|
||||
let future = compactTxStreamer.getBlockRange(
|
||||
BlockRange(
|
||||
startHeight: startHeight,
|
||||
endHeight: endHeight
|
||||
),
|
||||
callOptions: Self.callOptions(timeLimit: self.streamingCallTimeout),
|
||||
handler: { compactBlock in
|
||||
handler(ZcashCompactBlock(compactBlock: compactBlock))
|
||||
progress(
|
||||
BlockProgress(
|
||||
startHeight: startHeight,
|
||||
targetHeight: endHeight,
|
||||
progressHeight: BlockHeight(compactBlock.height)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
future.status.whenComplete { completionResult in
|
||||
switch completionResult {
|
||||
case .success(let status):
|
||||
switch status.code {
|
||||
case .ok:
|
||||
result(.success(GRPCResult.success))
|
||||
default:
|
||||
result(.failure(LightWalletServiceError.mapCode(status)))
|
||||
}
|
||||
case .failure(let error):
|
||||
result(.failure(LightWalletServiceError.genericError(error: error)))
|
||||
}
|
||||
}
|
||||
return future
|
||||
}
|
||||
|
||||
public func blockStream(
|
||||
startHeight: BlockHeight,
|
||||
endHeight: BlockHeight
|
||||
) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
||||
let stream = compactTxStreamerAsync.getBlockRange(
|
||||
BlockRange(
|
||||
startHeight: startHeight,
|
||||
endHeight: endHeight
|
||||
),
|
||||
callOptions: Self.callOptions(timeLimit: self.streamingCallTimeout)
|
||||
)
|
||||
|
||||
return AsyncThrowingStream { continuation in
|
||||
Task {
|
||||
do {
|
||||
for try await compactBlock in stream {
|
||||
continuation.yield(ZcashCompactBlock(compactBlock: compactBlock))
|
||||
}
|
||||
continuation.finish(throwing: nil)
|
||||
} catch {
|
||||
continuation.finish(throwing: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension LightWalletGRPCService: LightWalletService {
|
||||
public func closeConnection() {
|
||||
_ = channel.close()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Extensions
|
||||
|
|
|
@ -101,49 +101,102 @@ public protocol LightWalletServiceResponse {
|
|||
|
||||
extension SendResponse: LightWalletServiceResponse {}
|
||||
|
||||
public protocol LightWalletService {
|
||||
/**
|
||||
returns the info for this lightwalletd server (blocking)
|
||||
*/
|
||||
/// Blocking API - used for the testing purposes
|
||||
public protocol LightWalletServiceBlockingAPI {
|
||||
/// Returns the info for this lightwalletd server (blocking)
|
||||
func getInfo() throws -> LightWalletdInfo
|
||||
|
||||
/**
|
||||
returns the info for this lightwalletd server
|
||||
*/
|
||||
func getInfo(result: @escaping (Result<LightWalletdInfo, LightWalletServiceError>) -> Void)
|
||||
|
||||
/**
|
||||
Return the latest block height known to the service.
|
||||
|
||||
- Parameter result: a result containing the height or an Error
|
||||
*/
|
||||
func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void)
|
||||
|
||||
/**
|
||||
Return the latest block height known to the service.
|
||||
|
||||
- Parameter result: a result containing the height or an Error
|
||||
*/
|
||||
///
|
||||
/// Return the latest block height known to the service.
|
||||
/// - Parameter result: a result containing the height or an Error
|
||||
func latestBlockHeight() throws -> BlockHeight
|
||||
|
||||
/**
|
||||
Return the given range of blocks.
|
||||
|
||||
- Parameter range: the inclusive range to fetch.
|
||||
For instance if 1..5 is given, then every block in that will be fetched, including 1 and 5.
|
||||
Non blocking
|
||||
*/
|
||||
func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void )
|
||||
|
||||
/**
|
||||
Return the given range of blocks.
|
||||
|
||||
- Parameter range: the inclusive range to fetch.
|
||||
For instance if 1..5 is given, then every block in that will be fetched, including 1 and 5.
|
||||
blocking
|
||||
*/
|
||||
/// Return the given range of blocks.
|
||||
///
|
||||
/// - Parameter range: the inclusive range to fetch.
|
||||
/// For instance if 1..5 is given, then every block in that will be fetched, including 1 and 5.
|
||||
func blockRange(_ range: CompactBlockRange) throws -> [ZcashCompactBlock]
|
||||
|
||||
|
||||
/// Submits a raw transaction over lightwalletd. Blocking
|
||||
/// - Parameter spendTransaction: data representing the transaction to be sent
|
||||
/// - Throws: LightWalletServiceError
|
||||
/// - Returns: LightWalletServiceResponse
|
||||
func submit(spendTransaction: Data) throws -> LightWalletServiceResponse
|
||||
|
||||
/// Gets a transaction by id
|
||||
/// - Parameter txId: data representing the transaction ID
|
||||
/// - Throws: LightWalletServiceError
|
||||
/// - Returns: LightWalletServiceResponse
|
||||
func fetchTransaction(txId: Data) throws -> TransactionEntity
|
||||
|
||||
func fetchUTXOs(
|
||||
for tAddress: String,
|
||||
height: BlockHeight
|
||||
) throws -> [UnspentTransactionOutputEntity]
|
||||
|
||||
func fetchUTXOs(
|
||||
for tAddresses: [String],
|
||||
height: BlockHeight
|
||||
) throws -> [UnspentTransactionOutputEntity]
|
||||
}
|
||||
|
||||
public protocol LightWalletServiceNonBlockingAPI {
|
||||
/// Returns the info for this lightwalletd server
|
||||
@available(*, deprecated, message: "This function will be removed soon. Use the `getInfoAsync()` instead.")
|
||||
func getInfo(result: @escaping (Result<LightWalletdInfo, LightWalletServiceError>) -> Void)
|
||||
func getInfoAsync() async throws -> LightWalletdInfo
|
||||
|
||||
///
|
||||
/// Return the latest block height known to the service.
|
||||
/// - Parameter result: a result containing the height or an Error
|
||||
@available(*, deprecated, message: "This function will be removed soon. Use the `latestBlockHeightAsync()` instead.")
|
||||
func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void)
|
||||
func latestBlockHeightAsync() async throws -> BlockHeight
|
||||
|
||||
/// Return the given range of blocks.
|
||||
/// - Parameter range: the inclusive range to fetch.
|
||||
/// For instance if 1..5 is given, then every block in that will be fetched, including 1 and 5.
|
||||
@available(*, deprecated, message: "This function will be removed soon. Use the `blockRange(...) -> AsyncThrowingStream<ZcashCompactBlock, Error>` instead.")
|
||||
func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void)
|
||||
func blockRange(_ range: CompactBlockRange) -> AsyncThrowingStream<ZcashCompactBlock, Error>
|
||||
|
||||
/// Submits a raw transaction over lightwalletd. Non-Blocking
|
||||
/// - Parameter spendTransaction: data representing the transaction to be sent
|
||||
/// - Parameter result: escaping closure that takes a result containing either LightWalletServiceResponse or LightWalletServiceError
|
||||
@available(*, deprecated, message: "This function will be removed soon. Use the `submitAsync(spendTransaction: Data)` instead.")
|
||||
func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void)
|
||||
func submitAsync(spendTransaction: Data) async throws -> LightWalletServiceResponse
|
||||
|
||||
/// Gets a transaction by id
|
||||
/// - Parameter txId: data representing the transaction ID
|
||||
/// - Parameter result: handler for the result
|
||||
/// - Throws: LightWalletServiceError
|
||||
/// - Returns: LightWalletServiceResponse
|
||||
@available(*, deprecated, message: "This function will be removed soon. Use the `fetchTransactionAsync(txId: Data)` instead.")
|
||||
func fetchTransaction(
|
||||
txId: Data,
|
||||
result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void
|
||||
)
|
||||
func fetchTransactionAsync(txId: Data) async throws -> TransactionEntity
|
||||
|
||||
@available(*, deprecated, message: "This function will be removed soon. Use the `fetchUTXOs(for tAddress:...) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error>` instead.")
|
||||
func fetchUTXOs(
|
||||
for tAddress: String,
|
||||
height: BlockHeight,
|
||||
result: @escaping(Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
|
||||
)
|
||||
func fetchUTXOs(for tAddress: String, height: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error>
|
||||
|
||||
@available(*, deprecated, message: "This function will be removed soon. Use the `fetchUTXOs(for tAddresses:...) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error>` instead.")
|
||||
func fetchUTXOs(
|
||||
for tAddresses: [String],
|
||||
height: BlockHeight,
|
||||
result: @escaping(Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
|
||||
)
|
||||
func fetchUTXOs(for tAddresses: [String], height: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error>
|
||||
|
||||
@available(*, deprecated, message: "This function will be removed soon. Use the `blockStream(...) -> AsyncThrowingStream<ZcashCompactBlock, Error>` instead.")
|
||||
@discardableResult
|
||||
func blockStream(
|
||||
startHeight: BlockHeight,
|
||||
|
@ -153,62 +206,12 @@ public protocol LightWalletService {
|
|||
progress: @escaping (BlockProgress) -> Void
|
||||
) -> CancellableCall
|
||||
|
||||
/**
|
||||
Submits a raw transaction over lightwalletd. Non-Blocking
|
||||
- Parameter spendTransaction: data representing the transaction to be sent
|
||||
- Parameter result: escaping closure that takes a result containing either LightWalletServiceResponse or LightWalletServiceError
|
||||
*/
|
||||
func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void)
|
||||
|
||||
/**
|
||||
Submits a raw transaction over lightwalletd. Blocking
|
||||
- Parameter spendTransaction: data representing the transaction to be sent
|
||||
- Throws: LightWalletServiceError
|
||||
- Returns: LightWalletServiceResponse
|
||||
*/
|
||||
func submit(spendTransaction: Data) throws -> LightWalletServiceResponse
|
||||
|
||||
/**
|
||||
Gets a transaction by id
|
||||
- Parameter txId: data representing the transaction ID
|
||||
- Throws: LightWalletServiceError
|
||||
- Returns: LightWalletServiceResponse
|
||||
*/
|
||||
func fetchTransaction(txId: Data) throws -> TransactionEntity
|
||||
|
||||
/**
|
||||
Gets a transaction by id
|
||||
- Parameter txId: data representing the transaction ID
|
||||
- Parameter result: handler for the result
|
||||
- Throws: LightWalletServiceError
|
||||
- Returns: LightWalletServiceResponse
|
||||
*/
|
||||
func fetchTransaction(
|
||||
txId: Data,
|
||||
result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void
|
||||
)
|
||||
|
||||
func fetchUTXOs(
|
||||
for tAddress: String,
|
||||
height: BlockHeight
|
||||
) throws -> [UnspentTransactionOutputEntity]
|
||||
|
||||
func fetchUTXOs(
|
||||
for tAddress: String,
|
||||
height: BlockHeight,
|
||||
result: @escaping(Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
|
||||
)
|
||||
|
||||
func fetchUTXOs(
|
||||
for tAddresses: [String],
|
||||
height: BlockHeight
|
||||
) throws -> [UnspentTransactionOutputEntity]
|
||||
|
||||
func fetchUTXOs(
|
||||
for tAddresses: [String],
|
||||
height: BlockHeight,
|
||||
result: @escaping(Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
|
||||
)
|
||||
|
||||
func blockStream(
|
||||
startHeight: BlockHeight,
|
||||
endHeight: BlockHeight
|
||||
) -> AsyncThrowingStream<ZcashCompactBlock, Error>
|
||||
}
|
||||
|
||||
public protocol LightWalletService: LightWalletServiceNonBlockingAPI, LightWalletServiceBlockingAPI {
|
||||
func closeConnection()
|
||||
}
|
||||
|
|
|
@ -22,11 +22,15 @@
|
|||
//
|
||||
import GRPC
|
||||
import NIO
|
||||
import NIOConcurrencyHelpers
|
||||
import SwiftProtobuf
|
||||
|
||||
|
||||
/// Usage: instantiate CompactTxStreamerClient, then call methods of this protocol to make API calls.
|
||||
/// Usage: instantiate `CompactTxStreamerClient`, then call methods of this protocol to make API calls.
|
||||
internal protocol CompactTxStreamerClientProtocol: GRPCClient {
|
||||
var serviceName: String { get }
|
||||
var interceptors: CompactTxStreamerClientInterceptorFactoryProtocol? { get }
|
||||
|
||||
func getLatestBlock(
|
||||
_ request: ChainSpec,
|
||||
callOptions: CallOptions?
|
||||
|
@ -99,10 +103,12 @@ internal protocol CompactTxStreamerClientProtocol: GRPCClient {
|
|||
_ request: Duration,
|
||||
callOptions: CallOptions?
|
||||
) -> UnaryCall<Duration, PingResponse>
|
||||
|
||||
}
|
||||
|
||||
extension CompactTxStreamerClientProtocol {
|
||||
internal var serviceName: String {
|
||||
return "cash.z.wallet.sdk.rpc.CompactTxStreamer"
|
||||
}
|
||||
|
||||
/// Return the height of the tip of the best chain
|
||||
///
|
||||
|
@ -115,9 +121,10 @@ extension CompactTxStreamerClientProtocol {
|
|||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<ChainSpec, BlockID> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetLatestBlock",
|
||||
path: CompactTxStreamerClientMetadata.Methods.getLatestBlock.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetLatestBlockInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -132,9 +139,10 @@ extension CompactTxStreamerClientProtocol {
|
|||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<BlockID, CompactBlock> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetBlock",
|
||||
path: CompactTxStreamerClientMetadata.Methods.getBlock.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetBlockInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -151,9 +159,10 @@ extension CompactTxStreamerClientProtocol {
|
|||
handler: @escaping (CompactBlock) -> Void
|
||||
) -> ServerStreamingCall<BlockRange, CompactBlock> {
|
||||
return self.makeServerStreamingCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetBlockRange",
|
||||
path: CompactTxStreamerClientMetadata.Methods.getBlockRange.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetBlockRangeInterceptors() ?? [],
|
||||
handler: handler
|
||||
)
|
||||
}
|
||||
|
@ -169,9 +178,10 @@ extension CompactTxStreamerClientProtocol {
|
|||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<TxFilter, RawTransaction> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTransaction",
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTransaction.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTransactionInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -186,9 +196,10 @@ extension CompactTxStreamerClientProtocol {
|
|||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<RawTransaction, SendResponse> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/SendTransaction",
|
||||
path: CompactTxStreamerClientMetadata.Methods.sendTransaction.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeSendTransactionInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -205,9 +216,10 @@ extension CompactTxStreamerClientProtocol {
|
|||
handler: @escaping (RawTransaction) -> Void
|
||||
) -> ServerStreamingCall<TransparentAddressBlockFilter, RawTransaction> {
|
||||
return self.makeServerStreamingCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTaddressTxids",
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTaddressTxids.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTaddressTxidsInterceptors() ?? [],
|
||||
handler: handler
|
||||
)
|
||||
}
|
||||
|
@ -223,9 +235,10 @@ extension CompactTxStreamerClientProtocol {
|
|||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<AddressList, Balance> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTaddressBalance",
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTaddressBalance.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTaddressBalanceInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -241,8 +254,9 @@ extension CompactTxStreamerClientProtocol {
|
|||
callOptions: CallOptions? = nil
|
||||
) -> ClientStreamingCall<Address, Balance> {
|
||||
return self.makeClientStreamingCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTaddressBalanceStream",
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTaddressBalanceStream.path,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTaddressBalanceStreamInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -267,9 +281,10 @@ extension CompactTxStreamerClientProtocol {
|
|||
handler: @escaping (CompactTx) -> Void
|
||||
) -> ServerStreamingCall<Exclude, CompactTx> {
|
||||
return self.makeServerStreamingCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetMempoolTx",
|
||||
path: CompactTxStreamerClientMetadata.Methods.getMempoolTx.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetMempoolTxInterceptors() ?? [],
|
||||
handler: handler
|
||||
)
|
||||
}
|
||||
|
@ -288,9 +303,10 @@ extension CompactTxStreamerClientProtocol {
|
|||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<BlockID, TreeState> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTreeState",
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTreeState.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTreeStateInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -305,9 +321,10 @@ extension CompactTxStreamerClientProtocol {
|
|||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<GetAddressUtxosArg, GetAddressUtxosReplyList> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetAddressUtxos",
|
||||
path: CompactTxStreamerClientMetadata.Methods.getAddressUtxos.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetAddressUtxosInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -324,9 +341,10 @@ extension CompactTxStreamerClientProtocol {
|
|||
handler: @escaping (GetAddressUtxosReply) -> Void
|
||||
) -> ServerStreamingCall<GetAddressUtxosArg, GetAddressUtxosReply> {
|
||||
return self.makeServerStreamingCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetAddressUtxosStream",
|
||||
path: CompactTxStreamerClientMetadata.Methods.getAddressUtxosStream.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetAddressUtxosStreamInterceptors() ?? [],
|
||||
handler: handler
|
||||
)
|
||||
}
|
||||
|
@ -342,9 +360,10 @@ extension CompactTxStreamerClientProtocol {
|
|||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<Empty, LightdInfo> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetLightdInfo",
|
||||
path: CompactTxStreamerClientMetadata.Methods.getLightdInfo.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetLightdInfoInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -359,25 +378,679 @@ extension CompactTxStreamerClientProtocol {
|
|||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<Duration, PingResponse> {
|
||||
return self.makeUnaryCall(
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/Ping",
|
||||
path: CompactTxStreamerClientMetadata.Methods.ping.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makePingInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#if compiler(>=5.6)
|
||||
@available(*, deprecated)
|
||||
extension CompactTxStreamerClient: @unchecked Sendable {}
|
||||
#endif // compiler(>=5.6)
|
||||
|
||||
@available(*, deprecated, renamed: "CompactTxStreamerNIOClient")
|
||||
internal final class CompactTxStreamerClient: CompactTxStreamerClientProtocol {
|
||||
private let lock = Lock()
|
||||
private var _defaultCallOptions: CallOptions
|
||||
private var _interceptors: CompactTxStreamerClientInterceptorFactoryProtocol?
|
||||
internal let channel: GRPCChannel
|
||||
internal var defaultCallOptions: CallOptions
|
||||
internal var defaultCallOptions: CallOptions {
|
||||
get { self.lock.withLock { return self._defaultCallOptions } }
|
||||
set { self.lock.withLockVoid { self._defaultCallOptions = newValue } }
|
||||
}
|
||||
internal var interceptors: CompactTxStreamerClientInterceptorFactoryProtocol? {
|
||||
get { self.lock.withLock { return self._interceptors } }
|
||||
set { self.lock.withLockVoid { self._interceptors = newValue } }
|
||||
}
|
||||
|
||||
/// Creates a client for the cash.z.wallet.sdk.rpc.CompactTxStreamer service.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - channel: `GRPCChannel` to the service host.
|
||||
/// - defaultCallOptions: Options to use for each service call if the user doesn't provide them.
|
||||
internal init(channel: GRPCChannel, defaultCallOptions: CallOptions = CallOptions()) {
|
||||
/// - interceptors: A factory providing interceptors for each RPC.
|
||||
internal init(
|
||||
channel: GRPCChannel,
|
||||
defaultCallOptions: CallOptions = CallOptions(),
|
||||
interceptors: CompactTxStreamerClientInterceptorFactoryProtocol? = nil
|
||||
) {
|
||||
self.channel = channel
|
||||
self.defaultCallOptions = defaultCallOptions
|
||||
self._defaultCallOptions = defaultCallOptions
|
||||
self._interceptors = interceptors
|
||||
}
|
||||
}
|
||||
|
||||
internal struct CompactTxStreamerNIOClient: CompactTxStreamerClientProtocol {
|
||||
internal var channel: GRPCChannel
|
||||
internal var defaultCallOptions: CallOptions
|
||||
internal var interceptors: CompactTxStreamerClientInterceptorFactoryProtocol?
|
||||
|
||||
/// Creates a client for the cash.z.wallet.sdk.rpc.CompactTxStreamer service.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - channel: `GRPCChannel` to the service host.
|
||||
/// - defaultCallOptions: Options to use for each service call if the user doesn't provide them.
|
||||
/// - interceptors: A factory providing interceptors for each RPC.
|
||||
internal init(
|
||||
channel: GRPCChannel,
|
||||
defaultCallOptions: CallOptions = CallOptions(),
|
||||
interceptors: CompactTxStreamerClientInterceptorFactoryProtocol? = nil
|
||||
) {
|
||||
self.channel = channel
|
||||
self.defaultCallOptions = defaultCallOptions
|
||||
self.interceptors = interceptors
|
||||
}
|
||||
}
|
||||
|
||||
#if compiler(>=5.6)
|
||||
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||
internal protocol CompactTxStreamerAsyncClientProtocol: GRPCClient {
|
||||
static var serviceDescriptor: GRPCServiceDescriptor { get }
|
||||
var interceptors: CompactTxStreamerClientInterceptorFactoryProtocol? { get }
|
||||
|
||||
func makeGetLatestBlockCall(
|
||||
_ request: ChainSpec,
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncUnaryCall<ChainSpec, BlockID>
|
||||
|
||||
func makeGetBlockCall(
|
||||
_ request: BlockID,
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncUnaryCall<BlockID, CompactBlock>
|
||||
|
||||
func makeGetBlockRangeCall(
|
||||
_ request: BlockRange,
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncServerStreamingCall<BlockRange, CompactBlock>
|
||||
|
||||
func makeGetTransactionCall(
|
||||
_ request: TxFilter,
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncUnaryCall<TxFilter, RawTransaction>
|
||||
|
||||
func makeSendTransactionCall(
|
||||
_ request: RawTransaction,
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncUnaryCall<RawTransaction, SendResponse>
|
||||
|
||||
func makeGetTaddressTxidsCall(
|
||||
_ request: TransparentAddressBlockFilter,
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncServerStreamingCall<TransparentAddressBlockFilter, RawTransaction>
|
||||
|
||||
func makeGetTaddressBalanceCall(
|
||||
_ request: AddressList,
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncUnaryCall<AddressList, Balance>
|
||||
|
||||
func makeGetTaddressBalanceStreamCall(
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncClientStreamingCall<Address, Balance>
|
||||
|
||||
func makeGetMempoolTxCall(
|
||||
_ request: Exclude,
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncServerStreamingCall<Exclude, CompactTx>
|
||||
|
||||
func makeGetTreeStateCall(
|
||||
_ request: BlockID,
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncUnaryCall<BlockID, TreeState>
|
||||
|
||||
func makeGetAddressUtxosCall(
|
||||
_ request: GetAddressUtxosArg,
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncUnaryCall<GetAddressUtxosArg, GetAddressUtxosReplyList>
|
||||
|
||||
func makeGetAddressUtxosStreamCall(
|
||||
_ request: GetAddressUtxosArg,
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncServerStreamingCall<GetAddressUtxosArg, GetAddressUtxosReply>
|
||||
|
||||
func makeGetLightdInfoCall(
|
||||
_ request: Empty,
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncUnaryCall<Empty, LightdInfo>
|
||||
|
||||
func makePingCall(
|
||||
_ request: Duration,
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncUnaryCall<Duration, PingResponse>
|
||||
}
|
||||
|
||||
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||
extension CompactTxStreamerAsyncClientProtocol {
|
||||
internal static var serviceDescriptor: GRPCServiceDescriptor {
|
||||
return CompactTxStreamerClientMetadata.serviceDescriptor
|
||||
}
|
||||
|
||||
internal var interceptors: CompactTxStreamerClientInterceptorFactoryProtocol? {
|
||||
return nil
|
||||
}
|
||||
|
||||
internal func makeGetLatestBlockCall(
|
||||
_ request: ChainSpec,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncUnaryCall<ChainSpec, BlockID> {
|
||||
return self.makeAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getLatestBlock.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetLatestBlockInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func makeGetBlockCall(
|
||||
_ request: BlockID,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncUnaryCall<BlockID, CompactBlock> {
|
||||
return self.makeAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getBlock.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetBlockInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func makeGetBlockRangeCall(
|
||||
_ request: BlockRange,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncServerStreamingCall<BlockRange, CompactBlock> {
|
||||
return self.makeAsyncServerStreamingCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getBlockRange.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetBlockRangeInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func makeGetTransactionCall(
|
||||
_ request: TxFilter,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncUnaryCall<TxFilter, RawTransaction> {
|
||||
return self.makeAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTransaction.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTransactionInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func makeSendTransactionCall(
|
||||
_ request: RawTransaction,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncUnaryCall<RawTransaction, SendResponse> {
|
||||
return self.makeAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.sendTransaction.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeSendTransactionInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func makeGetTaddressTxidsCall(
|
||||
_ request: TransparentAddressBlockFilter,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncServerStreamingCall<TransparentAddressBlockFilter, RawTransaction> {
|
||||
return self.makeAsyncServerStreamingCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTaddressTxids.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTaddressTxidsInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func makeGetTaddressBalanceCall(
|
||||
_ request: AddressList,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncUnaryCall<AddressList, Balance> {
|
||||
return self.makeAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTaddressBalance.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTaddressBalanceInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func makeGetTaddressBalanceStreamCall(
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncClientStreamingCall<Address, Balance> {
|
||||
return self.makeAsyncClientStreamingCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTaddressBalanceStream.path,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTaddressBalanceStreamInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func makeGetMempoolTxCall(
|
||||
_ request: Exclude,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncServerStreamingCall<Exclude, CompactTx> {
|
||||
return self.makeAsyncServerStreamingCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getMempoolTx.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetMempoolTxInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func makeGetTreeStateCall(
|
||||
_ request: BlockID,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncUnaryCall<BlockID, TreeState> {
|
||||
return self.makeAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTreeState.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTreeStateInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func makeGetAddressUtxosCall(
|
||||
_ request: GetAddressUtxosArg,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncUnaryCall<GetAddressUtxosArg, GetAddressUtxosReplyList> {
|
||||
return self.makeAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getAddressUtxos.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetAddressUtxosInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func makeGetAddressUtxosStreamCall(
|
||||
_ request: GetAddressUtxosArg,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncServerStreamingCall<GetAddressUtxosArg, GetAddressUtxosReply> {
|
||||
return self.makeAsyncServerStreamingCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getAddressUtxosStream.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetAddressUtxosStreamInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func makeGetLightdInfoCall(
|
||||
_ request: Empty,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncUnaryCall<Empty, LightdInfo> {
|
||||
return self.makeAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getLightdInfo.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetLightdInfoInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func makePingCall(
|
||||
_ request: Duration,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncUnaryCall<Duration, PingResponse> {
|
||||
return self.makeAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.ping.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makePingInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||
extension CompactTxStreamerAsyncClientProtocol {
|
||||
internal func getLatestBlock(
|
||||
_ request: ChainSpec,
|
||||
callOptions: CallOptions? = nil
|
||||
) async throws -> BlockID {
|
||||
return try await self.performAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getLatestBlock.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetLatestBlockInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func getBlock(
|
||||
_ request: BlockID,
|
||||
callOptions: CallOptions? = nil
|
||||
) async throws -> CompactBlock {
|
||||
return try await self.performAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getBlock.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetBlockInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func getBlockRange(
|
||||
_ request: BlockRange,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncResponseStream<CompactBlock> {
|
||||
return self.performAsyncServerStreamingCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getBlockRange.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetBlockRangeInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func getTransaction(
|
||||
_ request: TxFilter,
|
||||
callOptions: CallOptions? = nil
|
||||
) async throws -> RawTransaction {
|
||||
return try await self.performAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTransaction.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTransactionInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func sendTransaction(
|
||||
_ request: RawTransaction,
|
||||
callOptions: CallOptions? = nil
|
||||
) async throws -> SendResponse {
|
||||
return try await self.performAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.sendTransaction.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeSendTransactionInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func getTaddressTxids(
|
||||
_ request: TransparentAddressBlockFilter,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncResponseStream<RawTransaction> {
|
||||
return self.performAsyncServerStreamingCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTaddressTxids.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTaddressTxidsInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func getTaddressBalance(
|
||||
_ request: AddressList,
|
||||
callOptions: CallOptions? = nil
|
||||
) async throws -> Balance {
|
||||
return try await self.performAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTaddressBalance.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTaddressBalanceInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func getTaddressBalanceStream<RequestStream>(
|
||||
_ requests: RequestStream,
|
||||
callOptions: CallOptions? = nil
|
||||
) async throws -> Balance where RequestStream: Sequence, RequestStream.Element == Address {
|
||||
return try await self.performAsyncClientStreamingCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTaddressBalanceStream.path,
|
||||
requests: requests,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTaddressBalanceStreamInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func getTaddressBalanceStream<RequestStream>(
|
||||
_ requests: RequestStream,
|
||||
callOptions: CallOptions? = nil
|
||||
) async throws -> Balance where RequestStream: AsyncSequence & Sendable, RequestStream.Element == Address {
|
||||
return try await self.performAsyncClientStreamingCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTaddressBalanceStream.path,
|
||||
requests: requests,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTaddressBalanceStreamInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func getMempoolTx(
|
||||
_ request: Exclude,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncResponseStream<CompactTx> {
|
||||
return self.performAsyncServerStreamingCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getMempoolTx.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetMempoolTxInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func getTreeState(
|
||||
_ request: BlockID,
|
||||
callOptions: CallOptions? = nil
|
||||
) async throws -> TreeState {
|
||||
return try await self.performAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getTreeState.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetTreeStateInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func getAddressUtxos(
|
||||
_ request: GetAddressUtxosArg,
|
||||
callOptions: CallOptions? = nil
|
||||
) async throws -> GetAddressUtxosReplyList {
|
||||
return try await self.performAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getAddressUtxos.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetAddressUtxosInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func getAddressUtxosStream(
|
||||
_ request: GetAddressUtxosArg,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncResponseStream<GetAddressUtxosReply> {
|
||||
return self.performAsyncServerStreamingCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getAddressUtxosStream.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetAddressUtxosStreamInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func getLightdInfo(
|
||||
_ request: Empty,
|
||||
callOptions: CallOptions? = nil
|
||||
) async throws -> LightdInfo {
|
||||
return try await self.performAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.getLightdInfo.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeGetLightdInfoInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
internal func ping(
|
||||
_ request: Duration,
|
||||
callOptions: CallOptions? = nil
|
||||
) async throws -> PingResponse {
|
||||
return try await self.performAsyncUnaryCall(
|
||||
path: CompactTxStreamerClientMetadata.Methods.ping.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makePingInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||
internal struct CompactTxStreamerAsyncClient: CompactTxStreamerAsyncClientProtocol {
|
||||
internal var channel: GRPCChannel
|
||||
internal var defaultCallOptions: CallOptions
|
||||
internal var interceptors: CompactTxStreamerClientInterceptorFactoryProtocol?
|
||||
|
||||
internal init(
|
||||
channel: GRPCChannel,
|
||||
defaultCallOptions: CallOptions = CallOptions(),
|
||||
interceptors: CompactTxStreamerClientInterceptorFactoryProtocol? = nil
|
||||
) {
|
||||
self.channel = channel
|
||||
self.defaultCallOptions = defaultCallOptions
|
||||
self.interceptors = interceptors
|
||||
}
|
||||
}
|
||||
|
||||
#endif // compiler(>=5.6)
|
||||
|
||||
internal protocol CompactTxStreamerClientInterceptorFactoryProtocol: GRPCSendable {
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'getLatestBlock'.
|
||||
func makeGetLatestBlockInterceptors() -> [ClientInterceptor<ChainSpec, BlockID>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'getBlock'.
|
||||
func makeGetBlockInterceptors() -> [ClientInterceptor<BlockID, CompactBlock>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'getBlockRange'.
|
||||
func makeGetBlockRangeInterceptors() -> [ClientInterceptor<BlockRange, CompactBlock>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'getTransaction'.
|
||||
func makeGetTransactionInterceptors() -> [ClientInterceptor<TxFilter, RawTransaction>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'sendTransaction'.
|
||||
func makeSendTransactionInterceptors() -> [ClientInterceptor<RawTransaction, SendResponse>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'getTaddressTxids'.
|
||||
func makeGetTaddressTxidsInterceptors() -> [ClientInterceptor<TransparentAddressBlockFilter, RawTransaction>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'getTaddressBalance'.
|
||||
func makeGetTaddressBalanceInterceptors() -> [ClientInterceptor<AddressList, Balance>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'getTaddressBalanceStream'.
|
||||
func makeGetTaddressBalanceStreamInterceptors() -> [ClientInterceptor<Address, Balance>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'getMempoolTx'.
|
||||
func makeGetMempoolTxInterceptors() -> [ClientInterceptor<Exclude, CompactTx>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'getTreeState'.
|
||||
func makeGetTreeStateInterceptors() -> [ClientInterceptor<BlockID, TreeState>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'getAddressUtxos'.
|
||||
func makeGetAddressUtxosInterceptors() -> [ClientInterceptor<GetAddressUtxosArg, GetAddressUtxosReplyList>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'getAddressUtxosStream'.
|
||||
func makeGetAddressUtxosStreamInterceptors() -> [ClientInterceptor<GetAddressUtxosArg, GetAddressUtxosReply>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'getLightdInfo'.
|
||||
func makeGetLightdInfoInterceptors() -> [ClientInterceptor<Empty, LightdInfo>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'ping'.
|
||||
func makePingInterceptors() -> [ClientInterceptor<Duration, PingResponse>]
|
||||
}
|
||||
|
||||
internal enum CompactTxStreamerClientMetadata {
|
||||
internal static let serviceDescriptor = GRPCServiceDescriptor(
|
||||
name: "CompactTxStreamer",
|
||||
fullName: "cash.z.wallet.sdk.rpc.CompactTxStreamer",
|
||||
methods: [
|
||||
CompactTxStreamerClientMetadata.Methods.getLatestBlock,
|
||||
CompactTxStreamerClientMetadata.Methods.getBlock,
|
||||
CompactTxStreamerClientMetadata.Methods.getBlockRange,
|
||||
CompactTxStreamerClientMetadata.Methods.getTransaction,
|
||||
CompactTxStreamerClientMetadata.Methods.sendTransaction,
|
||||
CompactTxStreamerClientMetadata.Methods.getTaddressTxids,
|
||||
CompactTxStreamerClientMetadata.Methods.getTaddressBalance,
|
||||
CompactTxStreamerClientMetadata.Methods.getTaddressBalanceStream,
|
||||
CompactTxStreamerClientMetadata.Methods.getMempoolTx,
|
||||
CompactTxStreamerClientMetadata.Methods.getTreeState,
|
||||
CompactTxStreamerClientMetadata.Methods.getAddressUtxos,
|
||||
CompactTxStreamerClientMetadata.Methods.getAddressUtxosStream,
|
||||
CompactTxStreamerClientMetadata.Methods.getLightdInfo,
|
||||
CompactTxStreamerClientMetadata.Methods.ping,
|
||||
]
|
||||
)
|
||||
|
||||
internal enum Methods {
|
||||
internal static let getLatestBlock = GRPCMethodDescriptor(
|
||||
name: "GetLatestBlock",
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetLatestBlock",
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
internal static let getBlock = GRPCMethodDescriptor(
|
||||
name: "GetBlock",
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetBlock",
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
internal static let getBlockRange = GRPCMethodDescriptor(
|
||||
name: "GetBlockRange",
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetBlockRange",
|
||||
type: GRPCCallType.serverStreaming
|
||||
)
|
||||
|
||||
internal static let getTransaction = GRPCMethodDescriptor(
|
||||
name: "GetTransaction",
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTransaction",
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
internal static let sendTransaction = GRPCMethodDescriptor(
|
||||
name: "SendTransaction",
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/SendTransaction",
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
internal static let getTaddressTxids = GRPCMethodDescriptor(
|
||||
name: "GetTaddressTxids",
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTaddressTxids",
|
||||
type: GRPCCallType.serverStreaming
|
||||
)
|
||||
|
||||
internal static let getTaddressBalance = GRPCMethodDescriptor(
|
||||
name: "GetTaddressBalance",
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTaddressBalance",
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
internal static let getTaddressBalanceStream = GRPCMethodDescriptor(
|
||||
name: "GetTaddressBalanceStream",
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTaddressBalanceStream",
|
||||
type: GRPCCallType.clientStreaming
|
||||
)
|
||||
|
||||
internal static let getMempoolTx = GRPCMethodDescriptor(
|
||||
name: "GetMempoolTx",
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetMempoolTx",
|
||||
type: GRPCCallType.serverStreaming
|
||||
)
|
||||
|
||||
internal static let getTreeState = GRPCMethodDescriptor(
|
||||
name: "GetTreeState",
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTreeState",
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
internal static let getAddressUtxos = GRPCMethodDescriptor(
|
||||
name: "GetAddressUtxos",
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetAddressUtxos",
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
internal static let getAddressUtxosStream = GRPCMethodDescriptor(
|
||||
name: "GetAddressUtxosStream",
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetAddressUtxosStream",
|
||||
type: GRPCCallType.serverStreaming
|
||||
)
|
||||
|
||||
internal static let getLightdInfo = GRPCMethodDescriptor(
|
||||
name: "GetLightdInfo",
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetLightdInfo",
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
internal static let ping = GRPCMethodDescriptor(
|
||||
name: "Ping",
|
||||
path: "/cash.z.wallet.sdk.rpc.CompactTxStreamer/Ping",
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ struct BlockID {
|
|||
|
||||
var height: UInt64 = 0
|
||||
|
||||
var hash: Data = SwiftProtobuf.Internal.emptyData
|
||||
var hash: Data = Data()
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
|
@ -95,7 +95,7 @@ struct TxFilter {
|
|||
var index: UInt64 = 0
|
||||
|
||||
/// transaction ID (hash, txid)
|
||||
var hash: Data = SwiftProtobuf.Internal.emptyData
|
||||
var hash: Data = Data()
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
|
@ -112,7 +112,7 @@ struct RawTransaction {
|
|||
// methods supported on all messages.
|
||||
|
||||
/// exact data returned by Zcash 'getrawtransaction'
|
||||
var data: Data = SwiftProtobuf.Internal.emptyData
|
||||
var data: Data = Data()
|
||||
|
||||
/// height that the transaction was mined (or -1)
|
||||
var height: UInt64 = 0
|
||||
|
@ -367,11 +367,11 @@ struct GetAddressUtxosReply {
|
|||
|
||||
var address: String = String()
|
||||
|
||||
var txid: Data = SwiftProtobuf.Internal.emptyData
|
||||
var txid: Data = Data()
|
||||
|
||||
var index: Int32 = 0
|
||||
|
||||
var script: Data = SwiftProtobuf.Internal.emptyData
|
||||
var script: Data = Data()
|
||||
|
||||
var valueZat: Int64 = 0
|
||||
|
||||
|
@ -394,6 +394,28 @@ struct GetAddressUtxosReplyList {
|
|||
init() {}
|
||||
}
|
||||
|
||||
#if swift(>=5.5) && canImport(_Concurrency)
|
||||
extension BlockID: @unchecked Sendable {}
|
||||
extension BlockRange: @unchecked Sendable {}
|
||||
extension TxFilter: @unchecked Sendable {}
|
||||
extension RawTransaction: @unchecked Sendable {}
|
||||
extension SendResponse: @unchecked Sendable {}
|
||||
extension ChainSpec: @unchecked Sendable {}
|
||||
extension Empty: @unchecked Sendable {}
|
||||
extension LightdInfo: @unchecked Sendable {}
|
||||
extension TransparentAddressBlockFilter: @unchecked Sendable {}
|
||||
extension Duration: @unchecked Sendable {}
|
||||
extension PingResponse: @unchecked Sendable {}
|
||||
extension Address: @unchecked Sendable {}
|
||||
extension AddressList: @unchecked Sendable {}
|
||||
extension Balance: @unchecked Sendable {}
|
||||
extension Exclude: @unchecked Sendable {}
|
||||
extension TreeState: @unchecked Sendable {}
|
||||
extension GetAddressUtxosArg: @unchecked Sendable {}
|
||||
extension GetAddressUtxosReply: @unchecked Sendable {}
|
||||
extension GetAddressUtxosReplyList: @unchecked Sendable {}
|
||||
#endif // swift(>=5.5) && canImport(_Concurrency)
|
||||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "cash.z.wallet.sdk.rpc"
|
||||
|
@ -407,9 +429,12 @@ extension BlockID: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularUInt64Field(value: &self.height)
|
||||
case 2: try decoder.decodeSingularBytesField(value: &self.hash)
|
||||
case 1: try { try decoder.decodeSingularUInt64Field(value: &self.height) }()
|
||||
case 2: try { try decoder.decodeSingularBytesField(value: &self.hash) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -442,21 +467,28 @@ extension BlockRange: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularMessageField(value: &self._start)
|
||||
case 2: try decoder.decodeSingularMessageField(value: &self._end)
|
||||
case 1: try { try decoder.decodeSingularMessageField(value: &self._start) }()
|
||||
case 2: try { try decoder.decodeSingularMessageField(value: &self._end) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if let v = self._start {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every if/case branch local when no optimizations
|
||||
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
|
||||
// https://github.com/apple/swift-protobuf/issues/1182
|
||||
try { if let v = self._start {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
|
||||
}
|
||||
if let v = self._end {
|
||||
} }()
|
||||
try { if let v = self._end {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
|
||||
}
|
||||
} }()
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
|
@ -478,19 +510,26 @@ extension TxFilter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularMessageField(value: &self._block)
|
||||
case 2: try decoder.decodeSingularUInt64Field(value: &self.index)
|
||||
case 3: try decoder.decodeSingularBytesField(value: &self.hash)
|
||||
case 1: try { try decoder.decodeSingularMessageField(value: &self._block) }()
|
||||
case 2: try { try decoder.decodeSingularUInt64Field(value: &self.index) }()
|
||||
case 3: try { try decoder.decodeSingularBytesField(value: &self.hash) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if let v = self._block {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every if/case branch local when no optimizations
|
||||
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
|
||||
// https://github.com/apple/swift-protobuf/issues/1182
|
||||
try { if let v = self._block {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
|
||||
}
|
||||
} }()
|
||||
if self.index != 0 {
|
||||
try visitor.visitSingularUInt64Field(value: self.index, fieldNumber: 2)
|
||||
}
|
||||
|
@ -518,9 +557,12 @@ extension RawTransaction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularBytesField(value: &self.data)
|
||||
case 2: try decoder.decodeSingularUInt64Field(value: &self.height)
|
||||
case 1: try { try decoder.decodeSingularBytesField(value: &self.data) }()
|
||||
case 2: try { try decoder.decodeSingularUInt64Field(value: &self.height) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -553,9 +595,12 @@ extension SendResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularInt32Field(value: &self.errorCode)
|
||||
case 2: try decoder.decodeSingularStringField(value: &self.errorMessage)
|
||||
case 1: try { try decoder.decodeSingularInt32Field(value: &self.errorCode) }()
|
||||
case 2: try { try decoder.decodeSingularStringField(value: &self.errorMessage) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -638,21 +683,24 @@ extension LightdInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
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)
|
||||
case 8: try decoder.decodeSingularStringField(value: &self.gitCommit)
|
||||
case 9: try decoder.decodeSingularStringField(value: &self.branch)
|
||||
case 10: try decoder.decodeSingularStringField(value: &self.buildDate)
|
||||
case 11: try decoder.decodeSingularStringField(value: &self.buildUser)
|
||||
case 12: try decoder.decodeSingularUInt64Field(value: &self.estimatedHeight)
|
||||
case 13: try decoder.decodeSingularStringField(value: &self.zcashdBuild)
|
||||
case 14: try decoder.decodeSingularStringField(value: &self.zcashdSubversion)
|
||||
case 1: try { try decoder.decodeSingularStringField(value: &self.version) }()
|
||||
case 2: try { try decoder.decodeSingularStringField(value: &self.vendor) }()
|
||||
case 3: try { try decoder.decodeSingularBoolField(value: &self.taddrSupport) }()
|
||||
case 4: try { try decoder.decodeSingularStringField(value: &self.chainName) }()
|
||||
case 5: try { try decoder.decodeSingularUInt64Field(value: &self.saplingActivationHeight) }()
|
||||
case 6: try { try decoder.decodeSingularStringField(value: &self.consensusBranchID) }()
|
||||
case 7: try { try decoder.decodeSingularUInt64Field(value: &self.blockHeight) }()
|
||||
case 8: try { try decoder.decodeSingularStringField(value: &self.gitCommit) }()
|
||||
case 9: try { try decoder.decodeSingularStringField(value: &self.branch) }()
|
||||
case 10: try { try decoder.decodeSingularStringField(value: &self.buildDate) }()
|
||||
case 11: try { try decoder.decodeSingularStringField(value: &self.buildUser) }()
|
||||
case 12: try { try decoder.decodeSingularUInt64Field(value: &self.estimatedHeight) }()
|
||||
case 13: try { try decoder.decodeSingularStringField(value: &self.zcashdBuild) }()
|
||||
case 14: try { try decoder.decodeSingularStringField(value: &self.zcashdSubversion) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -733,21 +781,28 @@ extension TransparentAddressBlockFilter: SwiftProtobuf.Message, SwiftProtobuf._M
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularStringField(value: &self.address)
|
||||
case 2: try decoder.decodeSingularMessageField(value: &self._range)
|
||||
case 1: try { try decoder.decodeSingularStringField(value: &self.address) }()
|
||||
case 2: try { try decoder.decodeSingularMessageField(value: &self._range) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every if/case branch local when no optimizations
|
||||
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
|
||||
// https://github.com/apple/swift-protobuf/issues/1182
|
||||
if !self.address.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.address, fieldNumber: 1)
|
||||
}
|
||||
if let v = self._range {
|
||||
try { if let v = self._range {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
|
||||
}
|
||||
} }()
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
|
@ -767,8 +822,11 @@ extension Duration: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularInt64Field(value: &self.intervalUs)
|
||||
case 1: try { try decoder.decodeSingularInt64Field(value: &self.intervalUs) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -797,9 +855,12 @@ extension PingResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularInt64Field(value: &self.entry)
|
||||
case 2: try decoder.decodeSingularInt64Field(value: &self.exit)
|
||||
case 1: try { try decoder.decodeSingularInt64Field(value: &self.entry) }()
|
||||
case 2: try { try decoder.decodeSingularInt64Field(value: &self.exit) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -831,8 +892,11 @@ extension Address: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularStringField(value: &self.address)
|
||||
case 1: try { try decoder.decodeSingularStringField(value: &self.address) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -860,8 +924,11 @@ extension AddressList: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeRepeatedStringField(value: &self.addresses)
|
||||
case 1: try { try decoder.decodeRepeatedStringField(value: &self.addresses) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -889,8 +956,11 @@ extension Balance: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularInt64Field(value: &self.valueZat)
|
||||
case 1: try { try decoder.decodeSingularInt64Field(value: &self.valueZat) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -918,8 +988,11 @@ extension Exclude: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeRepeatedBytesField(value: &self.txid)
|
||||
case 1: try { try decoder.decodeRepeatedBytesField(value: &self.txid) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -951,12 +1024,15 @@ extension TreeState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularStringField(value: &self.network)
|
||||
case 2: try decoder.decodeSingularUInt64Field(value: &self.height)
|
||||
case 3: try decoder.decodeSingularStringField(value: &self.hash)
|
||||
case 4: try decoder.decodeSingularUInt32Field(value: &self.time)
|
||||
case 5: try decoder.decodeSingularStringField(value: &self.tree)
|
||||
case 1: try { try decoder.decodeSingularStringField(value: &self.network) }()
|
||||
case 2: try { try decoder.decodeSingularUInt64Field(value: &self.height) }()
|
||||
case 3: try { try decoder.decodeSingularStringField(value: &self.hash) }()
|
||||
case 4: try { try decoder.decodeSingularUInt32Field(value: &self.time) }()
|
||||
case 5: try { try decoder.decodeSingularStringField(value: &self.tree) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -1002,10 +1078,13 @@ extension GetAddressUtxosArg: SwiftProtobuf.Message, SwiftProtobuf._MessageImple
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeRepeatedStringField(value: &self.addresses)
|
||||
case 2: try decoder.decodeSingularUInt64Field(value: &self.startHeight)
|
||||
case 3: try decoder.decodeSingularUInt32Field(value: &self.maxEntries)
|
||||
case 1: try { try decoder.decodeRepeatedStringField(value: &self.addresses) }()
|
||||
case 2: try { try decoder.decodeSingularUInt64Field(value: &self.startHeight) }()
|
||||
case 3: try { try decoder.decodeSingularUInt32Field(value: &self.maxEntries) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -1046,13 +1125,16 @@ extension GetAddressUtxosReply: SwiftProtobuf.Message, SwiftProtobuf._MessageImp
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeSingularBytesField(value: &self.txid)
|
||||
case 2: try decoder.decodeSingularInt32Field(value: &self.index)
|
||||
case 3: try decoder.decodeSingularBytesField(value: &self.script)
|
||||
case 4: try decoder.decodeSingularInt64Field(value: &self.valueZat)
|
||||
case 5: try decoder.decodeSingularUInt64Field(value: &self.height)
|
||||
case 6: try decoder.decodeSingularStringField(value: &self.address)
|
||||
case 1: try { try decoder.decodeSingularBytesField(value: &self.txid) }()
|
||||
case 2: try { try decoder.decodeSingularInt32Field(value: &self.index) }()
|
||||
case 3: try { try decoder.decodeSingularBytesField(value: &self.script) }()
|
||||
case 4: try { try decoder.decodeSingularInt64Field(value: &self.valueZat) }()
|
||||
case 5: try { try decoder.decodeSingularUInt64Field(value: &self.height) }()
|
||||
case 6: try { try decoder.decodeSingularStringField(value: &self.address) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -1100,8 +1182,11 @@ extension GetAddressUtxosReplyList: SwiftProtobuf.Message, SwiftProtobuf._Messag
|
|||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try decoder.decodeRepeatedMessageField(value: &self.addressUtxos)
|
||||
case 1: try { try decoder.decodeRepeatedMessageField(value: &self.addressUtxos) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
|
|
@ -632,7 +632,14 @@ public class SDKSynchronizer: Synchronizer {
|
|||
}
|
||||
|
||||
public func latestHeight(result: @escaping (Result<BlockHeight, Error>) -> Void) {
|
||||
blockProcessor.downloader.latestBlockHeight(result: result)
|
||||
Task {
|
||||
do {
|
||||
let latestBlockHeight = try await blockProcessor.downloader.latestBlockHeightAsync()
|
||||
result(.success(latestBlockHeight))
|
||||
} catch {
|
||||
result(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func latestHeight() throws -> BlockHeight {
|
||||
|
|
|
@ -40,31 +40,23 @@ class BlockDownloaderTests: XCTestCase {
|
|||
try? FileManager.default.removeItem(at: cacheDB)
|
||||
}
|
||||
|
||||
func testSmallDownloadAsync() {
|
||||
let expect = XCTestExpectation(description: self.description)
|
||||
expect.expectedFulfillmentCount = 3
|
||||
func testSmallDownloadAsync() async {
|
||||
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
|
||||
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
|
||||
|
||||
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
|
||||
downloader.downloadBlockRange(range) { error in
|
||||
expect.fulfill()
|
||||
XCTAssertNil(error)
|
||||
do {
|
||||
try await downloader.downloadBlockRangeAsync(range)
|
||||
|
||||
// check what was 'stored'
|
||||
self.storage.latestHeight { result in
|
||||
expect.fulfill()
|
||||
|
||||
XCTAssertTrue(self.validate(result: result, against: upperRange))
|
||||
|
||||
self.downloader.lastDownloadedBlockHeight { resultHeight in
|
||||
expect.fulfill()
|
||||
XCTAssertTrue(self.validate(result: resultHeight, against: upperRange))
|
||||
}
|
||||
}
|
||||
let latestHeight = try await self.storage.latestHeightAsync()
|
||||
XCTAssertEqual(latestHeight, upperRange)
|
||||
|
||||
let resultHeight = try await self.downloader.lastDownloadedBlockHeightAsync()
|
||||
XCTAssertEqual(resultHeight, upperRange)
|
||||
} catch {
|
||||
XCTFail("testSmallDownloadAsync() shouldn't fail")
|
||||
}
|
||||
|
||||
wait(for: [expect], timeout: 2)
|
||||
}
|
||||
|
||||
func testSmallDownload() {
|
||||
|
@ -94,7 +86,7 @@ class BlockDownloaderTests: XCTestCase {
|
|||
XCTAssertEqual(currentLatest, upperRange )
|
||||
}
|
||||
|
||||
func testFailure() {
|
||||
func testFailure() async {
|
||||
let awfulDownloader = CompactBlockDownloader(
|
||||
service: AwfulLightWalletService(
|
||||
latestBlockHeight: self.network.constants.saplingActivationHeight + 1000,
|
||||
|
@ -103,18 +95,16 @@ class BlockDownloaderTests: XCTestCase {
|
|||
storage: ZcashConsoleFakeStorage()
|
||||
)
|
||||
|
||||
let expect = XCTestExpectation(description: self.description)
|
||||
expect.expectedFulfillmentCount = 1
|
||||
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
|
||||
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
|
||||
|
||||
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
|
||||
|
||||
awfulDownloader.downloadBlockRange(range) { error in
|
||||
expect.fulfill()
|
||||
|
||||
do {
|
||||
try await awfulDownloader.downloadBlockRangeAsync(range)
|
||||
} catch {
|
||||
XCTAssertNotNil(error)
|
||||
}
|
||||
wait(for: [expect], timeout: 2)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,21 @@ class LightWalletServiceTests: XCTestCase {
|
|||
wait(for: [expect], timeout: 10)
|
||||
}
|
||||
|
||||
func testHundredBlocks() async throws {
|
||||
let count = 99
|
||||
let lowerRange: BlockHeight = network.constants.saplingActivationHeight
|
||||
let upperRange: BlockHeight = network.constants.saplingActivationHeight + count
|
||||
let blockRange = lowerRange ... upperRange
|
||||
|
||||
var blocks: [ZcashCompactBlock] = []
|
||||
for try await block in service.blockRange(blockRange) {
|
||||
blocks.append(block)
|
||||
}
|
||||
XCTAssertEqual(blocks.count, blockRange.count)
|
||||
XCTAssertEqual(blocks[0].height, lowerRange)
|
||||
XCTAssertEqual(blocks.last!.height, upperRange)
|
||||
}
|
||||
|
||||
func testSyncBlockRange() {
|
||||
let lowerRange: BlockHeight = network.constants.saplingActivationHeight
|
||||
let upperRange: BlockHeight = network.constants.saplingActivationHeight + 99
|
||||
|
@ -74,6 +89,18 @@ class LightWalletServiceTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
func testSyncBlockRange() async throws {
|
||||
let lowerRange: BlockHeight = network.constants.saplingActivationHeight
|
||||
let upperRange: BlockHeight = network.constants.saplingActivationHeight + 99
|
||||
let blockRange = lowerRange ... upperRange
|
||||
|
||||
var blocks: [ZcashCompactBlock] = []
|
||||
for try await block in service.blockRange(blockRange) {
|
||||
blocks.append(block)
|
||||
}
|
||||
XCTAssertEqual(blocks.count, blockRange.count)
|
||||
}
|
||||
|
||||
func testLatestBlock() {
|
||||
let expect = XCTestExpectation(description: self.description)
|
||||
service.latestBlockHeight { result in
|
||||
|
@ -88,4 +115,9 @@ class LightWalletServiceTests: XCTestCase {
|
|||
|
||||
wait(for: [expect], timeout: 10)
|
||||
}
|
||||
|
||||
func testLatestBlock() async throws {
|
||||
let height = try await service.latestBlockHeightAsync()
|
||||
XCTAssertTrue(height > self.network.constants.saplingActivationHeight)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,12 @@ class CompactBlockStorageTests: XCTestCase {
|
|||
func testEmptyStorage() {
|
||||
XCTAssertEqual(try! compactBlockDao.latestHeight(), BlockHeight.empty())
|
||||
}
|
||||
|
||||
|
||||
func testEmptyStorageAsync() async throws {
|
||||
let latestHeight = try await compactBlockDao.latestHeightAsync()
|
||||
XCTAssertEqual(latestHeight, BlockHeight.empty())
|
||||
}
|
||||
|
||||
func testStoreThousandBlocks() {
|
||||
let initialHeight = try! compactBlockDao.latestHeight()
|
||||
let startHeight = self.network.constants.saplingActivationHeight
|
||||
|
@ -38,6 +43,19 @@ class CompactBlockStorageTests: XCTestCase {
|
|||
XCTAssertEqual(latestHeight, finalHeight)
|
||||
}
|
||||
|
||||
func testStoreThousandBlocksAsync() async throws {
|
||||
let initialHeight = try! compactBlockDao.latestHeight()
|
||||
let startHeight = self.network.constants.saplingActivationHeight
|
||||
let blockCount = Int(1_000)
|
||||
let finalHeight = startHeight + blockCount
|
||||
|
||||
try TestDbBuilder.seed(db: compactBlockDao, with: startHeight...finalHeight)
|
||||
|
||||
let latestHeight = try await compactBlockDao.latestHeightAsync()
|
||||
XCTAssertNotEqual(initialHeight, latestHeight)
|
||||
XCTAssertEqual(latestHeight, finalHeight)
|
||||
}
|
||||
|
||||
func testStoreOneBlockFromEmpty() {
|
||||
let initialHeight = try! compactBlockDao.latestHeight()
|
||||
guard initialHeight == BlockHeight.empty() else {
|
||||
|
@ -61,6 +79,24 @@ class CompactBlockStorageTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
func testStoreOneBlockFromEmptyAsync() async throws {
|
||||
let initialHeight = try await compactBlockDao.latestHeightAsync()
|
||||
guard initialHeight == BlockHeight.empty() else {
|
||||
XCTFail("database not empty, latest height: \(initialHeight)")
|
||||
return
|
||||
}
|
||||
|
||||
let expectedHeight = BlockHeight(123_456)
|
||||
guard let block = StubBlockCreator.createRandomDataBlock(with: expectedHeight) else {
|
||||
XCTFail("could not create randem block with height: \(expectedHeight)")
|
||||
return
|
||||
}
|
||||
try await compactBlockDao.writeAsync(blocks: [block])
|
||||
|
||||
let result = try await compactBlockDao.latestHeightAsync()
|
||||
XCTAssertEqual(result, expectedHeight)
|
||||
}
|
||||
|
||||
func testRewindTo() {
|
||||
let startHeight = self.network.constants.saplingActivationHeight
|
||||
let blockCount = Int(1_000)
|
||||
|
@ -82,4 +118,17 @@ class CompactBlockStorageTests: XCTestCase {
|
|||
XCTFail("Rewind latest block failed with error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func testRewindToAsync() async throws {
|
||||
let startHeight = self.network.constants.saplingActivationHeight
|
||||
let blockCount = Int(1_000)
|
||||
let finalHeight = startHeight + blockCount
|
||||
|
||||
try TestDbBuilder.seed(db: compactBlockDao, with: startHeight...finalHeight)
|
||||
let rewindHeight = BlockHeight(finalHeight - 233)
|
||||
|
||||
try await compactBlockDao.rewindAsync(to: rewindHeight)
|
||||
let latestHeight = try await compactBlockDao.latestHeightAsync()
|
||||
XCTAssertEqual(latestHeight, rewindHeight - 1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,6 +75,10 @@ class DarksideWalletService: LightWalletService {
|
|||
)
|
||||
}
|
||||
|
||||
func blockStream(startHeight: BlockHeight, endHeight: BlockHeight) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
||||
service.blockStream(startHeight: startHeight, endHeight: endHeight)
|
||||
}
|
||||
|
||||
func getInfo() throws -> LightWalletdInfo {
|
||||
try service.getInfo()
|
||||
}
|
||||
|
@ -87,7 +91,11 @@ class DarksideWalletService: LightWalletService {
|
|||
}
|
||||
|
||||
func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
||||
return []
|
||||
try service.fetchUTXOs(for: tAddress, height: height)
|
||||
}
|
||||
|
||||
func fetchUTXOs(for tAddresses: [String], height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
||||
try service.fetchUTXOs(for: tAddresses, height: height)
|
||||
}
|
||||
|
||||
func fetchUTXOs(
|
||||
|
@ -98,8 +106,8 @@ class DarksideWalletService: LightWalletService {
|
|||
service.fetchUTXOs(for: tAddress, height: height, result: result)
|
||||
}
|
||||
|
||||
func fetchUTXOs(for tAddresses: [String], height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
||||
try service.fetchUTXOs(for: tAddresses, height: height)
|
||||
func fetchUTXOs(for tAddress: String, height: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
||||
service.fetchUTXOs(for: tAddress, height: height)
|
||||
}
|
||||
|
||||
func fetchUTXOs(
|
||||
|
@ -109,7 +117,10 @@ class DarksideWalletService: LightWalletService {
|
|||
) {
|
||||
service.fetchUTXOs(for: tAddresses, height: height, result: result)
|
||||
}
|
||||
|
||||
|
||||
func fetchUTXOs(for tAddresses: [String], height: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
||||
service.fetchUTXOs(for: tAddresses, height: height)
|
||||
}
|
||||
|
||||
func fetchTransaction(txId: Data) throws -> TransactionEntity {
|
||||
try service.fetchTransaction(txId: txId)
|
||||
|
@ -222,6 +233,26 @@ class DarksideWalletService: LightWalletService {
|
|||
func clearAddedUTXOs() throws {
|
||||
_ = try darksideService.clearAddressUtxo(Empty(), callOptions: nil).response.wait()
|
||||
}
|
||||
|
||||
func getInfoAsync() async throws -> LightWalletdInfo {
|
||||
try service.getInfo()
|
||||
}
|
||||
|
||||
func latestBlockHeightAsync() async throws -> BlockHeight {
|
||||
try service.latestBlockHeight()
|
||||
}
|
||||
|
||||
func blockRange(_ range: CompactBlockRange) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
||||
service.blockRange(range)
|
||||
}
|
||||
|
||||
func submitAsync(spendTransaction: Data) async throws -> LightWalletServiceResponse {
|
||||
try service.submit(spendTransaction: spendTransaction)
|
||||
}
|
||||
|
||||
func fetchTransactionAsync(txId: Data) async throws -> TransactionEntity {
|
||||
try service.fetchTransaction(txId: txId)
|
||||
}
|
||||
}
|
||||
|
||||
enum DarksideWalletDConstants: NetworkConstants {
|
||||
|
|
|
@ -35,6 +35,10 @@ class MockLightWalletService: LightWalletService {
|
|||
return MockCancellable()
|
||||
}
|
||||
|
||||
func blockStream(startHeight: BlockHeight, endHeight: BlockHeight) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
||||
AsyncThrowingStream { _ in }
|
||||
}
|
||||
|
||||
func getInfo() throws -> LightWalletdInfo {
|
||||
guard let info = mockLightDInfo else {
|
||||
throw LightWalletServiceError.generalError(message: "Not Implemented")
|
||||
|
@ -59,28 +63,30 @@ class MockLightWalletService: LightWalletService {
|
|||
[]
|
||||
}
|
||||
|
||||
func fetchUTXOs(for tAddresses: [String], height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
||||
[]
|
||||
}
|
||||
|
||||
func fetchUTXOs(
|
||||
for tAddress: String,
|
||||
height: BlockHeight,
|
||||
result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
|
||||
) {
|
||||
}
|
||||
|
||||
func fetchUTXOs(for tAddresses: [String], height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
||||
[]
|
||||
|
||||
func fetchUTXOs(for tAddress: String, height: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
||||
AsyncThrowingStream { _ in }
|
||||
}
|
||||
|
||||
|
||||
func fetchUTXOs(
|
||||
for tAddresses: [String],
|
||||
height: BlockHeight,
|
||||
result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
|
||||
) {
|
||||
}
|
||||
|
||||
func fetchUTXOs(
|
||||
for tAddress: String,
|
||||
result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
|
||||
) {
|
||||
|
||||
func fetchUTXOs(for tAddresses: [String], height: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
||||
AsyncThrowingStream { _ in }
|
||||
}
|
||||
|
||||
private var service: LightWalletService
|
||||
|
@ -126,4 +132,35 @@ class MockLightWalletService: LightWalletService {
|
|||
|
||||
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
|
||||
}
|
||||
|
||||
func getInfoAsync() async throws -> LightWalletdInfo {
|
||||
guard let info = mockLightDInfo else {
|
||||
throw LightWalletServiceError.generalError(message: "Not Implemented")
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
func latestBlockHeightAsync() async throws -> BlockHeight {
|
||||
latestHeight
|
||||
}
|
||||
|
||||
func blockRange(_ range: CompactBlockRange) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
||||
service.blockRange(range)
|
||||
}
|
||||
|
||||
func submitAsync(spendTransaction: Data) async throws -> LightWalletServiceResponse {
|
||||
LightWalletServiceMockResponse(errorCode: 0, errorMessage: "", unknownFields: UnknownStorage())
|
||||
}
|
||||
|
||||
func fetchTransactionAsync(txId: Data) async throws -> TransactionEntity {
|
||||
Transaction(id: 1, transactionId: Data(), created: "Today", transactionIndex: 1, expiryHeight: -1, minedHeight: -1, raw: nil)
|
||||
}
|
||||
|
||||
func fetchUTXOsAsync(for tAddress: String, height: BlockHeight) async throws -> [UnspentTransactionOutputEntity] {
|
||||
[]
|
||||
}
|
||||
|
||||
func fetchUTXOsAsync(for tAddresses: [String], height: BlockHeight) async throws -> [UnspentTransactionOutputEntity] {
|
||||
[]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,18 @@ import Foundation
|
|||
@testable import ZcashLightClientKit
|
||||
|
||||
class ZcashConsoleFakeStorage: CompactBlockRepository {
|
||||
func latestHeightAsync() async throws -> BlockHeight {
|
||||
latestBlockHeight
|
||||
}
|
||||
|
||||
func writeAsync(blocks: [ZcashCompactBlock]) async throws {
|
||||
fakeSave(blocks: blocks)
|
||||
}
|
||||
|
||||
func rewindAsync(to height: BlockHeight) async throws {
|
||||
fakeRewind(to: height)
|
||||
}
|
||||
|
||||
func latestHeight() throws -> Int {
|
||||
return self.latestBlockHeight
|
||||
}
|
||||
|
@ -29,12 +41,6 @@ class ZcashConsoleFakeStorage: CompactBlockRepository {
|
|||
self.latestBlockHeight = latestBlockHeight
|
||||
}
|
||||
|
||||
func latestHeight(result: @escaping (Result<BlockHeight, Error>) -> Void) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
||||
result(.success(self.latestBlockHeight))
|
||||
}
|
||||
}
|
||||
|
||||
private func fakeSave(blocks: [ZcashCompactBlock]) {
|
||||
blocks.forEach {
|
||||
LoggerProxy.debug("saving block \($0)")
|
||||
|
@ -42,20 +48,6 @@ class ZcashConsoleFakeStorage: CompactBlockRepository {
|
|||
}
|
||||
}
|
||||
|
||||
func write(blocks: [ZcashCompactBlock], completion: ((Error?) -> Void)?) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
||||
self.fakeSave(blocks: blocks)
|
||||
completion?(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func rewind(to height: BlockHeight, completion: ((Error?) -> Void)?) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
||||
self.fakeRewind(to: height)
|
||||
completion?(nil)
|
||||
}
|
||||
}
|
||||
|
||||
private func fakeRewind(to height: BlockHeight) {
|
||||
LoggerProxy.debug("rewind to \(height)")
|
||||
self.latestBlockHeight = min(self.latestBlockHeight, height)
|
||||
|
|
|
@ -33,6 +33,10 @@ class AwfulLightWalletService: MockLightWalletService {
|
|||
}
|
||||
}
|
||||
|
||||
override func blockRange(_ range: CompactBlockRange) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
||||
AsyncThrowingStream { continuation in continuation.finish(throwing: LightWalletServiceError.invalidBlock) }
|
||||
}
|
||||
|
||||
override func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
result(.failure(LightWalletServiceError.invalidBlock))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'ZcashLightClientKit'
|
||||
s.version = '0.16.7-beta'
|
||||
s.version = '0.16.8-beta'
|
||||
s.summary = 'Zcash Light Client wallet SDK for iOS'
|
||||
|
||||
s.description = <<-DESC
|
||||
|
|
17
changelog.md
17
changelog.md
|
@ -1,3 +1,20 @@
|
|||
# 0.16.8-beta
|
||||
Checkpoints added:
|
||||
Mainnet
|
||||
````
|
||||
Sources/ZcashLightClientKit/Resources/checkpoints/mainnet/1775000.json
|
||||
Sources/ZcashLightClientKit/Resources/checkpoints/mainnet/1777500.json
|
||||
Sources/ZcashLightClientKit/Resources/checkpoints/mainnet/1780000.json
|
||||
Sources/ZcashLightClientKit/Resources/checkpoints/mainnet/1782500.json
|
||||
Sources/ZcashLightClientKit/Resources/checkpoints/mainnet/1785000.json
|
||||
````
|
||||
|
||||
Testnet
|
||||
````
|
||||
Sources/ZcashLightClientKit/Resources/checkpoints/testnet/2000000.json
|
||||
Sources/ZcashLightClientKit/Resources/checkpoints/testnet/2010000.json
|
||||
````
|
||||
|
||||
# 0.16.7-beta
|
||||
- [#455] revert queue priority downgrade changes from [#435] (#456)
|
||||
|
||||
|
|
Loading…
Reference in New Issue