Merge branch 'master' into merge-master
This commit is contained in:
commit
7f480e417d
|
@ -92,11 +92,7 @@ extension CompactBlockStorage: CompactBlockRepository {
|
||||||
return try await task.value
|
return try await task.value
|
||||||
}
|
}
|
||||||
|
|
||||||
func write(blocks: [ZcashCompactBlock]) throws {
|
func write(blocks: [ZcashCompactBlock]) async throws {
|
||||||
try insert(blocks)
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeAsync(blocks: [ZcashCompactBlock]) async throws {
|
|
||||||
let task = Task(priority: .userInitiated) {
|
let task = Task(priority: .userInitiated) {
|
||||||
try insert(blocks)
|
try insert(blocks)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,18 +16,11 @@ enum CompactBlockDownloadError: Error {
|
||||||
Represents what a compact block downloaded should provide to its clients
|
Represents what a compact block downloaded should provide to its clients
|
||||||
*/
|
*/
|
||||||
public protocol CompactBlockDownloading {
|
public protocol CompactBlockDownloading {
|
||||||
|
|
||||||
/**
|
|
||||||
Downloads and stores the given block range.
|
|
||||||
Blocking
|
|
||||||
*/
|
|
||||||
func downloadBlockRange(_ range: CompactBlockRange) throws
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Downloads and stores the given block range.
|
Downloads and stores the given block range.
|
||||||
Non-Blocking
|
Non-Blocking
|
||||||
*/
|
*/
|
||||||
func downloadBlockRangeAsync(_ heightRange: CompactBlockRange) async throws
|
func downloadBlockRange(_ heightRange: CompactBlockRange) async throws
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Restore the download progress up to the given height.
|
Restore the download progress up to the given height.
|
||||||
|
@ -69,37 +62,11 @@ public protocol CompactBlockDownloading {
|
||||||
/**
|
/**
|
||||||
Gets the transaction for the Id given
|
Gets the transaction for the Id given
|
||||||
- Parameter txId: Data representing the transaction Id
|
- Parameter txId: Data representing the transaction Id
|
||||||
- Returns: a transaction entity with the requested transaction
|
|
||||||
- Throws: An error if the fetch failed
|
|
||||||
*/
|
*/
|
||||||
func fetchTransaction(txId: Data) throws -> TransactionEntity
|
func fetchTransaction(txId: Data) async throws -> TransactionEntity
|
||||||
|
|
||||||
/**
|
|
||||||
Gets the transaction for the Id given
|
|
||||||
- Parameter txId: Data representing the transaction Id
|
|
||||||
*/
|
|
||||||
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(tAddress: String, startHeight: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error>
|
||||||
|
|
||||||
func fetchUnspentTransactionOutputs(tAddresses: [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(
|
|
||||||
tAddresses: [String],
|
|
||||||
startHeight: BlockHeight,
|
|
||||||
result: @escaping (Result<[UnspentTransactionOutputEntity], Error>) -> Void
|
|
||||||
)
|
|
||||||
|
|
||||||
func fetchUnspentTransactionOutputs(tAddresses: [String], startHeight: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error>
|
func fetchUnspentTransactionOutputs(tAddresses: [String], startHeight: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error>
|
||||||
|
|
||||||
func closeConnection()
|
func closeConnection()
|
||||||
|
@ -128,44 +95,10 @@ extension CompactBlockDownloader: CompactBlockDownloading {
|
||||||
lightwalletService.closeConnection()
|
lightwalletService.closeConnection()
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchUnspentTransactionOutputs(tAddresses: [String], startHeight: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
|
||||||
try lightwalletService.fetchUTXOs(for: tAddresses, height: startHeight)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchUnspentTransactionOutputs(
|
|
||||||
tAddresses: [String],
|
|
||||||
startHeight: BlockHeight,
|
|
||||||
result: @escaping (Result<[UnspentTransactionOutputEntity], Error>) -> Void
|
|
||||||
) {
|
|
||||||
lightwalletService.fetchUTXOs(for: tAddresses, height: startHeight) { fetchResult in
|
|
||||||
switch fetchResult {
|
|
||||||
case .success(let utxos):
|
|
||||||
result(.success(utxos))
|
|
||||||
case .failure(let error):
|
|
||||||
result(.failure(error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchUnspentTransactionOutputs(tAddresses: [String], startHeight: BlockHeight ) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
func fetchUnspentTransactionOutputs(tAddresses: [String], startHeight: BlockHeight ) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
||||||
lightwalletService.fetchUTXOs(for: tAddresses, height: startHeight)
|
lightwalletService.fetchUTXOs(for: tAddresses, height: startHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchUnspentTransactionOutputs(tAddress: String, startHeight: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
|
||||||
try lightwalletService.fetchUTXOs(for: tAddress, height: startHeight)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchUnspentTransactionOutputs(tAddress: String, startHeight: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], Error>) -> Void) {
|
|
||||||
lightwalletService.fetchUTXOs(for: tAddress, height: startHeight) { fetchResult in
|
|
||||||
switch fetchResult {
|
|
||||||
case .success(let utxos):
|
|
||||||
result(.success(utxos))
|
|
||||||
case .failure(let error):
|
|
||||||
result(.failure(error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchUnspentTransactionOutputs(tAddress: String, startHeight: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
func fetchUnspentTransactionOutputs(tAddress: String, startHeight: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
||||||
lightwalletService.fetchUTXOs(for: tAddress, height: startHeight)
|
lightwalletService.fetchUTXOs(for: tAddress, height: startHeight)
|
||||||
}
|
}
|
||||||
|
@ -178,19 +111,14 @@ extension CompactBlockDownloader: CompactBlockDownloading {
|
||||||
try lightwalletService.latestBlockHeight()
|
try lightwalletService.latestBlockHeight()
|
||||||
}
|
}
|
||||||
|
|
||||||
func downloadBlockRange(_ range: CompactBlockRange) throws {
|
func downloadBlockRange( _ heightRange: CompactBlockRange) async throws {
|
||||||
let blocks = try lightwalletService.blockRange(range)
|
|
||||||
try storage.write(blocks: blocks)
|
|
||||||
}
|
|
||||||
|
|
||||||
func downloadBlockRangeAsync( _ heightRange: CompactBlockRange) async throws {
|
|
||||||
let stream: AsyncThrowingStream<ZcashCompactBlock, Error> = lightwalletService.blockRange(heightRange)
|
let stream: AsyncThrowingStream<ZcashCompactBlock, Error> = lightwalletService.blockRange(heightRange)
|
||||||
do {
|
do {
|
||||||
var compactBlocks: [ZcashCompactBlock] = []
|
var compactBlocks: [ZcashCompactBlock] = []
|
||||||
for try await compactBlock in stream {
|
for try await compactBlock in stream {
|
||||||
compactBlocks.append(compactBlock)
|
compactBlocks.append(compactBlock)
|
||||||
}
|
}
|
||||||
try await self.storage.writeAsync(blocks: compactBlocks)
|
try await self.storage.write(blocks: compactBlocks)
|
||||||
} catch {
|
} catch {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
@ -221,11 +149,7 @@ extension CompactBlockDownloader: CompactBlockDownloading {
|
||||||
try self.storage.latestHeight()
|
try self.storage.latestHeight()
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchTransaction(txId: Data) throws -> TransactionEntity {
|
func fetchTransaction(txId: Data) async throws -> TransactionEntity {
|
||||||
try lightwalletService.fetchTransaction(txId: txId)
|
try await lightwalletService.fetchTransaction(txId: txId)
|
||||||
}
|
|
||||||
|
|
||||||
func fetchTransactionAsync(txId: Data) async throws -> TransactionEntity {
|
|
||||||
try await lightwalletService.fetchTransactionAsync(txId: txId)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,7 @@ extension CompactBlockProcessor {
|
||||||
try Task.checkCancellation()
|
try Task.checkCancellation()
|
||||||
buffer.append(zcashCompactBlock)
|
buffer.append(zcashCompactBlock)
|
||||||
if buffer.count >= blockBufferSize {
|
if buffer.count >= blockBufferSize {
|
||||||
// TODO: writeAsync doesn't make sense here, awaiting it or calling blocking API have the same result and impact
|
try await storage.write(blocks: buffer)
|
||||||
try storage.write(blocks: buffer)
|
|
||||||
buffer.removeAll(keepingCapacity: true)
|
buffer.removeAll(keepingCapacity: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,8 +53,7 @@ extension CompactBlockProcessor {
|
||||||
)
|
)
|
||||||
notifyProgress(.download(progress))
|
notifyProgress(.download(progress))
|
||||||
}
|
}
|
||||||
// TODO: writeAsync doesn't make sense here, awaiting it or calling blocking API have the same result and impact
|
try await storage.write(blocks: buffer)
|
||||||
try storage.write(blocks: buffer)
|
|
||||||
buffer.removeAll(keepingCapacity: true)
|
buffer.removeAll(keepingCapacity: true)
|
||||||
} catch {
|
} catch {
|
||||||
guard let err = error as? LightWalletServiceError, case .userCancelled = err else {
|
guard let err = error as? LightWalletServiceError, case .userCancelled = err else {
|
||||||
|
@ -73,7 +71,7 @@ extension CompactBlockProcessor {
|
||||||
try Task.checkCancellation()
|
try Task.checkCancellation()
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try await downloader.downloadBlockRangeAsync(range)
|
try await downloader.downloadBlockRange(range)
|
||||||
} catch {
|
} catch {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ extension CompactBlockProcessor {
|
||||||
private func enhance(transaction: TransactionEntity) async throws -> ConfirmedTransactionEntity {
|
private func enhance(transaction: TransactionEntity) async throws -> ConfirmedTransactionEntity {
|
||||||
LoggerProxy.debug("Zoom.... Enhance... Tx: \(transaction.transactionId.toHexStringTxId())")
|
LoggerProxy.debug("Zoom.... Enhance... Tx: \(transaction.transactionId.toHexStringTxId())")
|
||||||
|
|
||||||
let transaction = try await downloader.fetchTransactionAsync(txId: transaction.transactionId)
|
let transaction = try await downloader.fetchTransaction(txId: transaction.transactionId)
|
||||||
|
|
||||||
let transactionID = transaction.transactionId.toHexStringTxId()
|
let transactionID = transaction.transactionId.toHexStringTxId()
|
||||||
let block = String(describing: transaction.minedHeight)
|
let block = String(describing: transaction.minedHeight)
|
||||||
|
|
|
@ -601,14 +601,9 @@ public class CompactBlockProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateServer(completionBlock: @escaping (() -> Void)) {
|
func validateServer(completionBlock: @escaping (() -> Void)) {
|
||||||
self.service.getInfo(result: { [weak self] result in
|
Task { @MainActor in
|
||||||
guard let self = self else { return }
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success(let info):
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
|
||||||
guard let self = self else { return }
|
|
||||||
do {
|
do {
|
||||||
|
let info = try await self.service.getInfo()
|
||||||
try Self.validateServerInfo(
|
try Self.validateServerInfo(
|
||||||
info,
|
info,
|
||||||
saplingActivation: self.config.saplingActivation,
|
saplingActivation: self.config.saplingActivation,
|
||||||
|
@ -616,16 +611,13 @@ public class CompactBlockProcessor {
|
||||||
rustBackend: self.rustBackend
|
rustBackend: self.rustBackend
|
||||||
)
|
)
|
||||||
completionBlock()
|
completionBlock()
|
||||||
|
} catch let error as LightWalletServiceError {
|
||||||
|
self.severeFailure(error.mapToProcessorError())
|
||||||
} catch {
|
} catch {
|
||||||
self.severeFailure(error)
|
self.severeFailure(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .failure(let error):
|
|
||||||
self.severeFailure(error.mapToProcessorError())
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Processes new blocks on the given range based on the configuration set for this instance
|
/// Processes new blocks on the given range based on the configuration set for this instance
|
||||||
func processNewBlocks(range: CompactBlockRange) {
|
func processNewBlocks(range: CompactBlockRange) {
|
||||||
|
@ -1178,25 +1170,8 @@ extension CompactBlockProcessor {
|
||||||
rustBackend: ZcashRustBackendWelding.Type
|
rustBackend: ZcashRustBackendWelding.Type
|
||||||
) async throws -> NextState {
|
) async throws -> NextState {
|
||||||
let task = Task(priority: .userInitiated) {
|
let task = Task(priority: .userInitiated) {
|
||||||
// TODO: refactor to async call, issue 463, PR 493
|
do {
|
||||||
// https://github.com/zcash/ZcashLightClientKit/issues/463
|
let info = try await service.getInfo()
|
||||||
try nextState(
|
|
||||||
service: service,
|
|
||||||
downloader: downloader,
|
|
||||||
config: config,
|
|
||||||
rustBackend: rustBackend
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return try await task.value
|
|
||||||
}
|
|
||||||
|
|
||||||
static func nextState(
|
|
||||||
service: LightWalletService,
|
|
||||||
downloader: CompactBlockDownloading,
|
|
||||||
config: Configuration,
|
|
||||||
rustBackend: ZcashRustBackendWelding.Type
|
|
||||||
) throws -> NextState {
|
|
||||||
let info = try service.getInfo()
|
|
||||||
|
|
||||||
try CompactBlockProcessor.validateServerInfo(
|
try CompactBlockProcessor.validateServerInfo(
|
||||||
info,
|
info,
|
||||||
|
@ -1211,7 +1186,7 @@ extension CompactBlockProcessor {
|
||||||
let latestBlockheight = try service.latestBlockHeight()
|
let latestBlockheight = try service.latestBlockHeight()
|
||||||
|
|
||||||
if latestDownloadedBlockHeight < latestBlockheight {
|
if latestDownloadedBlockHeight < latestBlockheight {
|
||||||
return .processNewBlocks(
|
return NextState.processNewBlocks(
|
||||||
range: CompactBlockProcessor.nextBatchBlockRange(
|
range: CompactBlockProcessor.nextBatchBlockRange(
|
||||||
latestHeight: latestBlockheight,
|
latestHeight: latestBlockheight,
|
||||||
latestDownloadedHeight: latestDownloadedBlockHeight,
|
latestDownloadedHeight: latestDownloadedBlockHeight,
|
||||||
|
@ -1223,6 +1198,11 @@ extension CompactBlockProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
return .wait(latestHeight: latestBlockheight, latestDownloadHeight: latestBlockheight)
|
return .wait(latestHeight: latestBlockheight, latestDownloadHeight: latestBlockheight)
|
||||||
|
} catch {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return try await task.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,21 +31,14 @@ protocol CompactBlockRepository {
|
||||||
*/
|
*/
|
||||||
func latestHeightAsync() async throws -> BlockHeight
|
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
|
|
||||||
- Parameter blocks: the compact blocks that will be written to storage
|
|
||||||
- Throws: an error when there's a failure
|
|
||||||
*/
|
|
||||||
func write(blocks: [ZcashCompactBlock]) throws
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Write the given blocks to this store, which may be anything from an in-memory cache to a DB.
|
Write the given blocks to this store, which may be anything from an in-memory cache to a DB.
|
||||||
Non-Blocking
|
Non-Blocking
|
||||||
- Parameters:
|
- Parameters:
|
||||||
- Parameter blocks: array of blocks to be written to storage
|
- Parameter blocks: array of blocks to be written to storage
|
||||||
|
- Throws: an error when there's a failure
|
||||||
*/
|
*/
|
||||||
func writeAsync(blocks: [ZcashCompactBlock]) async throws
|
func write(blocks: [ZcashCompactBlock]) async throws
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Remove every block above and including the given height.
|
Remove every block above and including the given height.
|
||||||
|
|
|
@ -10,6 +10,7 @@ import Foundation
|
||||||
import GRPC
|
import GRPC
|
||||||
import NIO
|
import NIO
|
||||||
import NIOHPACK
|
import NIOHPACK
|
||||||
|
import NIOTransportServices
|
||||||
|
|
||||||
public typealias Channel = GRPC.GRPCChannel
|
public typealias Channel = GRPC.GRPCChannel
|
||||||
|
|
||||||
|
@ -127,8 +128,8 @@ public class LightWalletGRPCService {
|
||||||
self.singleCallTimeout = TimeLimit.timeout(.milliseconds(singleCallTimeout))
|
self.singleCallTimeout = TimeLimit.timeout(.milliseconds(singleCallTimeout))
|
||||||
|
|
||||||
let connectionBuilder = secure ?
|
let connectionBuilder = secure ?
|
||||||
ClientConnection.usingPlatformAppropriateTLS(for: MultiThreadedEventLoopGroup(numberOfThreads: 1)) :
|
ClientConnection.usingPlatformAppropriateTLS(for: NIOTSEventLoopGroup(loopCount: 1, defaultQoS: .default)) :
|
||||||
ClientConnection.insecure(group: MultiThreadedEventLoopGroup(numberOfThreads: 1))
|
ClientConnection.insecure(group: NIOTSEventLoopGroup(loopCount: 1, defaultQoS: .default))
|
||||||
|
|
||||||
let channel = connectionBuilder
|
let channel = connectionBuilder
|
||||||
.withConnectivityStateDelegate(connectionManager, executingOn: queue)
|
.withConnectivityStateDelegate(connectionManager, executingOn: queue)
|
||||||
|
@ -188,11 +189,11 @@ public class LightWalletGRPCService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - LightWalletServiceBlockingAPI
|
// MARK: - LightWalletService
|
||||||
|
|
||||||
extension LightWalletGRPCService: LightWalletServiceBlockingAPI {
|
extension LightWalletGRPCService: LightWalletService {
|
||||||
public func getInfo() throws -> LightWalletdInfo {
|
public func getInfo() async throws -> LightWalletdInfo {
|
||||||
try compactTxStreamer.getLightdInfo(Empty()).response.wait()
|
try await compactTxStreamerAsync.getLightdInfo(Empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
public func latestBlockHeight() throws -> BlockHeight {
|
public func latestBlockHeight() throws -> BlockHeight {
|
||||||
|
@ -202,160 +203,12 @@ extension LightWalletGRPCService: LightWalletServiceBlockingAPI {
|
||||||
return height
|
return height
|
||||||
}
|
}
|
||||||
|
|
||||||
public func blockRange(_ range: CompactBlockRange) throws -> [ZcashCompactBlock] {
|
|
||||||
var blocks: [CompactBlock] = []
|
|
||||||
|
|
||||||
let response = compactTxStreamer.getBlockRange(
|
|
||||||
range.blockRange(),
|
|
||||||
handler: { blocks.append($0) }
|
|
||||||
)
|
|
||||||
|
|
||||||
let status = try response.status.wait()
|
|
||||||
|
|
||||||
switch status.code {
|
|
||||||
case .ok:
|
|
||||||
return blocks.asZcashCompactBlocks()
|
|
||||||
default:
|
|
||||||
throw LightWalletServiceError.mapCode(status)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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 fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
|
||||||
let arg = GetAddressUtxosArg.with { utxoArgs in
|
|
||||||
utxoArgs.addresses = [tAddress]
|
|
||||||
utxoArgs.startHeight = UInt64(height)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
return try self.compactTxStreamer.getAddressUtxos(arg).response.wait().addressUtxos.map { reply in
|
|
||||||
UTXO(
|
|
||||||
id: nil,
|
|
||||||
address: tAddress,
|
|
||||||
prevoutTxId: reply.txid,
|
|
||||||
prevoutIndex: Int(reply.index),
|
|
||||||
script: reply.script,
|
|
||||||
valueZat: Int(reply.valueZat),
|
|
||||||
height: Int(reply.height),
|
|
||||||
spentInTx: nil
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
throw error.mapToServiceError()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
public func latestBlockHeightAsync() async throws -> BlockHeight {
|
||||||
try await BlockHeight(compactTxStreamerAsync.getLatestBlock(ChainSpec()).height)
|
let blockID = try await compactTxStreamerAsync.getLatestBlock(ChainSpec())
|
||||||
}
|
guard let blockHeight = Int(exactly: blockID.height) else {
|
||||||
|
throw LightWalletServiceError.generalError(message: "error creating blockheight from BlockID \(blockID)")
|
||||||
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()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return blockHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
public func blockRange(_ range: CompactBlockRange) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
public func blockRange(_ range: CompactBlockRange) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
||||||
|
@ -375,48 +228,16 @@ extension LightWalletGRPCService: LightWalletServiceNonBlockingAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func submit(spendTransaction: Data, result: @escaping (Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
|
public func submit(spendTransaction: Data) async throws -> LightWalletServiceResponse {
|
||||||
do {
|
do {
|
||||||
let transaction = try RawTransaction(serializedData: spendTransaction)
|
let transaction = RawTransaction.with { $0.data = 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)
|
return try await compactTxStreamerAsync.sendTransaction(transaction)
|
||||||
} catch {
|
} catch {
|
||||||
throw LightWalletServiceError.sentFailed(error: error)
|
throw LightWalletServiceError.sentFailed(error: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
|
public func fetchTransaction(txId: Data) async throws -> TransactionEntity {
|
||||||
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()
|
var txFilter = TxFilter()
|
||||||
txFilter.hash = txId
|
txFilter.hash = txId
|
||||||
|
|
||||||
|
@ -472,52 +293,6 @@ extension LightWalletGRPCService: LightWalletServiceNonBlockingAPI {
|
||||||
return fetchUTXOs(for: [tAddress], height: height)
|
return fetchUTXOs(for: [tAddress], height: height)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func fetchUTXOs(
|
|
||||||
for tAddresses: [String],
|
|
||||||
height: BlockHeight,
|
|
||||||
result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
|
|
||||||
) {
|
|
||||||
guard !tAddresses.isEmpty else {
|
|
||||||
return result(.success([])) // FIXME: throw a real error
|
|
||||||
}
|
|
||||||
|
|
||||||
var utxos: [UnspentTransactionOutputEntity] = []
|
|
||||||
self.queue.async { [weak self] in
|
|
||||||
guard let self = self else { return }
|
|
||||||
let args = GetAddressUtxosArg.with { utxoArgs in
|
|
||||||
utxoArgs.addresses = tAddresses
|
|
||||||
utxoArgs.startHeight = UInt64(height)
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
let response = try self.compactTxStreamer.getAddressUtxosStream(args) { reply in
|
|
||||||
utxos.append(
|
|
||||||
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
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.status
|
|
||||||
.wait()
|
|
||||||
|
|
||||||
switch response.code {
|
|
||||||
case .ok:
|
|
||||||
result(.success(utxos))
|
|
||||||
default:
|
|
||||||
result(.failure(.mapCode(response)))
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
result(.failure(error.mapToServiceError()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func fetchUTXOs(
|
public func fetchUTXOs(
|
||||||
for tAddresses: [String],
|
for tAddresses: [String],
|
||||||
height: BlockHeight
|
height: BlockHeight
|
||||||
|
@ -557,48 +332,6 @@ extension LightWalletGRPCService: LightWalletServiceNonBlockingAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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(
|
public func blockStream(
|
||||||
startHeight: BlockHeight,
|
startHeight: BlockHeight,
|
||||||
endHeight: BlockHeight
|
endHeight: BlockHeight
|
||||||
|
@ -624,9 +357,7 @@ extension LightWalletGRPCService: LightWalletServiceNonBlockingAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
extension LightWalletGRPCService: LightWalletService {
|
|
||||||
public func closeConnection() {
|
public func closeConnection() {
|
||||||
_ = channel.close()
|
_ = channel.close()
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,117 +101,40 @@ public protocol LightWalletServiceResponse {
|
||||||
|
|
||||||
extension SendResponse: LightWalletServiceResponse {}
|
extension SendResponse: LightWalletServiceResponse {}
|
||||||
|
|
||||||
/// Blocking API - used for the testing purposes
|
public protocol LightWalletService {
|
||||||
public protocol LightWalletServiceBlockingAPI {
|
/// Returns the info for this lightwalletd server
|
||||||
/// Returns the info for this lightwalletd server (blocking)
|
func getInfo() async throws -> LightWalletdInfo
|
||||||
func getInfo() throws -> LightWalletdInfo
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Return the latest block height known to the service.
|
/// Return the latest block height known to the service.
|
||||||
/// - Parameter result: a result containing the height or an Error
|
/// Blocking API
|
||||||
func latestBlockHeight() throws -> BlockHeight
|
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.
|
|
||||||
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.
|
/// 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
|
func latestBlockHeightAsync() async throws -> BlockHeight
|
||||||
|
|
||||||
/// Return the given range of blocks.
|
/// Return the given range of blocks.
|
||||||
/// - Parameter range: the inclusive range to fetch.
|
/// - 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.
|
/// 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>
|
func blockRange(_ range: CompactBlockRange) -> AsyncThrowingStream<ZcashCompactBlock, Error>
|
||||||
|
|
||||||
/// Submits a raw transaction over lightwalletd. Non-Blocking
|
/// Submits a raw transaction over lightwalletd. Non-Blocking
|
||||||
/// - Parameter spendTransaction: data representing the transaction to be sent
|
/// - Parameter spendTransaction: data representing the transaction to be sent
|
||||||
/// - Parameter result: escaping closure that takes a result containing either LightWalletServiceResponse or LightWalletServiceError
|
func submit(spendTransaction: Data) async throws -> LightWalletServiceResponse
|
||||||
@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
|
/// Gets a transaction by id
|
||||||
/// - Parameter txId: data representing the transaction ID
|
/// - Parameter txId: data representing the transaction ID
|
||||||
/// - Parameter result: handler for the result
|
|
||||||
/// - Throws: LightWalletServiceError
|
/// - Throws: LightWalletServiceError
|
||||||
/// - Returns: LightWalletServiceResponse
|
/// - Returns: LightWalletServiceResponse
|
||||||
@available(*, deprecated, message: "This function will be removed soon. Use the `fetchTransactionAsync(txId: Data)` instead.")
|
func fetchTransaction(txId: Data) async throws -> TransactionEntity
|
||||||
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>
|
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>
|
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,
|
|
||||||
endHeight: BlockHeight,
|
|
||||||
result: @escaping (Result<GRPCResult, LightWalletServiceError>) -> Void,
|
|
||||||
handler: @escaping (ZcashCompactBlock) -> Void,
|
|
||||||
progress: @escaping (BlockProgress) -> Void
|
|
||||||
) -> CancellableCall
|
|
||||||
|
|
||||||
func blockStream(
|
func blockStream(
|
||||||
startHeight: BlockHeight,
|
startHeight: BlockHeight,
|
||||||
endHeight: BlockHeight
|
endHeight: BlockHeight
|
||||||
) -> AsyncThrowingStream<ZcashCompactBlock, Error>
|
) -> AsyncThrowingStream<ZcashCompactBlock, Error>
|
||||||
}
|
|
||||||
|
|
||||||
public protocol LightWalletService: LightWalletServiceNonBlockingAPI, LightWalletServiceBlockingAPI {
|
|
||||||
func closeConnection()
|
func closeConnection()
|
||||||
}
|
}
|
||||||
|
|
|
@ -584,29 +584,23 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
try blockProcessor.downloader.latestBlockHeight()
|
try blockProcessor.downloader.latestBlockHeight()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func latestUTXOs(address: String, result: @escaping (Result<[UnspentTransactionOutputEntity], Error>) -> Void) {
|
public func latestUTXOs(address: String) async throws -> [UnspentTransactionOutputEntity] {
|
||||||
guard initializer.isValidTransparentAddress(address) else {
|
guard initializer.isValidTransparentAddress(address) else {
|
||||||
result(.failure(SynchronizerError.generalError(message: "invalid t-address")))
|
throw SynchronizerError.generalError(message: "invalid t-address")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initializer.lightWalletService.fetchUTXOs(
|
let stream = initializer.lightWalletService.fetchUTXOs(for: address, height: network.constants.saplingActivationHeight)
|
||||||
for: address,
|
|
||||||
height: network.constants.saplingActivationHeight
|
|
||||||
) { [weak self] fetchResult in
|
|
||||||
guard let self = self else { return }
|
|
||||||
switch fetchResult {
|
|
||||||
case .success(let utxos):
|
|
||||||
do {
|
do {
|
||||||
|
var utxos: [UnspentTransactionOutputEntity] = []
|
||||||
|
for try await transactionEntity in stream {
|
||||||
|
utxos.append(transactionEntity)
|
||||||
|
}
|
||||||
try self.utxoRepository.clearAll(address: address)
|
try self.utxoRepository.clearAll(address: address)
|
||||||
try self.utxoRepository.store(utxos: utxos)
|
try self.utxoRepository.store(utxos: utxos)
|
||||||
result(.success(utxos))
|
return utxos
|
||||||
} catch {
|
} catch {
|
||||||
result(.failure(SynchronizerError.generalError(message: "\(error)")))
|
throw SynchronizerError.generalError(message: "\(error)")
|
||||||
}
|
|
||||||
case .failure(let error):
|
|
||||||
result(.failure(SynchronizerError.connectionFailed(message: error)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ class PersistentTransactionManager: OutboundTransactionManager {
|
||||||
pendingTransaction: PendingTransactionEntity
|
pendingTransaction: PendingTransactionEntity
|
||||||
) async throws -> PendingTransactionEntity {
|
) async throws -> PendingTransactionEntity {
|
||||||
do {
|
do {
|
||||||
let encodedTransaction = try self.encoder.createShieldingTransaction(
|
let encodedTransaction = try await self.encoder.createShieldingTransaction(
|
||||||
spendingKey: spendingKey,
|
spendingKey: spendingKey,
|
||||||
memoBytes: try pendingTransaction.memo.intoMemoBytes(),
|
memoBytes: try pendingTransaction.memo.intoMemoBytes(),
|
||||||
from: pendingTransaction.accountIndex
|
from: pendingTransaction.accountIndex
|
||||||
|
@ -102,7 +102,7 @@ class PersistentTransactionManager: OutboundTransactionManager {
|
||||||
pendingTransaction: PendingTransactionEntity
|
pendingTransaction: PendingTransactionEntity
|
||||||
) async throws -> PendingTransactionEntity {
|
) async throws -> PendingTransactionEntity {
|
||||||
do {
|
do {
|
||||||
let encodedTransaction = try self.encoder.createTransaction(
|
let encodedTransaction = try await self.encoder.createTransaction(
|
||||||
spendingKey: spendingKey,
|
spendingKey: spendingKey,
|
||||||
zatoshi: pendingTransaction.value,
|
zatoshi: pendingTransaction.value,
|
||||||
to: pendingTransaction.toAddress,
|
to: pendingTransaction.toAddress,
|
||||||
|
@ -155,7 +155,7 @@ class PersistentTransactionManager: OutboundTransactionManager {
|
||||||
throw TransactionManagerError.internalInconsistency(storedTx)
|
throw TransactionManagerError.internalInconsistency(storedTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
let response = try self.service.submit(spendTransaction: raw)
|
let response = try await self.service.submit(spendTransaction: raw)
|
||||||
let transaction = try self.update(transaction: storedTx, on: response)
|
let transaction = try self.update(transaction: storedTx, on: response)
|
||||||
|
|
||||||
guard response.errorCode >= 0 else {
|
guard response.errorCode >= 0 else {
|
||||||
|
|
|
@ -48,21 +48,19 @@ protocol TransactionEncoder {
|
||||||
/// Non-blocking
|
/// Non-blocking
|
||||||
///
|
///
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - Parameter spendingKey: a `SaplingExtendedSpendingKey` containing the spending key
|
/// - Parameter spendingKey: a `UnifiedSpendingKey` containing the spending key
|
||||||
/// - Parameter zatoshi: the amount to send in `Zatoshi`
|
/// - Parameter zatoshi: the amount to send in `Zatoshi`
|
||||||
/// - Parameter to: string containing the recipient address
|
/// - Parameter to: string containing the recipient address
|
||||||
/// - Parameter MemoBytes: string containing the memo (optional)
|
/// - Parameter MemoBytes: string containing the memo (optional)
|
||||||
/// - Parameter accountIndex: index of the account that will be used to send the funds
|
/// - Parameter accountIndex: index of the account that will be used to send the funds
|
||||||
/// - Parameter result: a non escaping closure that receives a Result containing either an EncodedTransaction or a /// TransactionEncoderError
|
|
||||||
// swiftlint:disable:next function_parameter_count
|
// swiftlint:disable:next function_parameter_count
|
||||||
func createTransaction(
|
func createTransaction(
|
||||||
spendingKey: UnifiedSpendingKey,
|
spendingKey: UnifiedSpendingKey,
|
||||||
zatoshi: Zatoshi,
|
zatoshi: Zatoshi,
|
||||||
to address: String,
|
to address: String,
|
||||||
memoBytes: MemoBytes,
|
memoBytes: MemoBytes,
|
||||||
from accountIndex: Int,
|
from accountIndex: Int
|
||||||
result: @escaping TransactionEncoderResultBlock
|
) async throws -> EncodedTransaction
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a transaction that will attempt to shield transparent funds that are present on the cacheDB .throwing an exception whenever things are missing. When the provided wallet implementation doesn't throw an exception, we wrap the issue into a descriptive exception ourselves (rather than using double-bangs for things).
|
Creates a transaction that will attempt to shield transparent funds that are present on the cacheDB .throwing an exception whenever things are missing. When the provided wallet implementation doesn't throw an exception, we wrap the issue into a descriptive exception ourselves (rather than using double-bangs for things).
|
||||||
|
|
|
@ -10,7 +10,6 @@ import Foundation
|
||||||
class WalletTransactionEncoder: TransactionEncoder {
|
class WalletTransactionEncoder: TransactionEncoder {
|
||||||
var rustBackend: ZcashRustBackendWelding.Type
|
var rustBackend: ZcashRustBackendWelding.Type
|
||||||
var repository: TransactionRepository
|
var repository: TransactionRepository
|
||||||
var queue: DispatchQueue
|
|
||||||
|
|
||||||
private var outputParamsURL: URL
|
private var outputParamsURL: URL
|
||||||
private var spendParamsURL: URL
|
private var spendParamsURL: URL
|
||||||
|
@ -34,7 +33,6 @@ class WalletTransactionEncoder: TransactionEncoder {
|
||||||
self.outputParamsURL = outputParams
|
self.outputParamsURL = outputParams
|
||||||
self.spendParamsURL = spendParams
|
self.spendParamsURL = spendParams
|
||||||
self.networkType = networkType
|
self.networkType = networkType
|
||||||
self.queue = DispatchQueue(label: "wallet.transaction.encoder.serial.queue")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
convenience init(initializer: Initializer) {
|
convenience init(initializer: Initializer) {
|
||||||
|
@ -55,7 +53,7 @@ class WalletTransactionEncoder: TransactionEncoder {
|
||||||
to address: String,
|
to address: String,
|
||||||
memoBytes: MemoBytes,
|
memoBytes: MemoBytes,
|
||||||
from accountIndex: Int
|
from accountIndex: Int
|
||||||
) throws -> EncodedTransaction {
|
) async throws -> EncodedTransaction {
|
||||||
let txId = try createSpend(
|
let txId = try createSpend(
|
||||||
spendingKey: spendingKey,
|
spendingKey: spendingKey,
|
||||||
zatoshi: zatoshi,
|
zatoshi: zatoshi,
|
||||||
|
@ -78,35 +76,6 @@ class WalletTransactionEncoder: TransactionEncoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// swiftlint:disable:next function_parameter_count
|
|
||||||
func createTransaction(
|
|
||||||
spendingKey: UnifiedSpendingKey,
|
|
||||||
zatoshi: Zatoshi,
|
|
||||||
to address: String,
|
|
||||||
memoBytes: MemoBytes,
|
|
||||||
from accountIndex: Int,
|
|
||||||
result: @escaping TransactionEncoderResultBlock
|
|
||||||
) {
|
|
||||||
queue.async { [weak self] in
|
|
||||||
guard let self = self else { return }
|
|
||||||
do {
|
|
||||||
result(
|
|
||||||
.success(
|
|
||||||
try self.createTransaction(
|
|
||||||
spendingKey: spendingKey,
|
|
||||||
zatoshi: zatoshi,
|
|
||||||
to: address,
|
|
||||||
memoBytes: memoBytes,
|
|
||||||
from: accountIndex
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} catch {
|
|
||||||
result(.failure(error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSpend(
|
func createSpend(
|
||||||
spendingKey: UnifiedSpendingKey,
|
spendingKey: UnifiedSpendingKey,
|
||||||
zatoshi: Zatoshi,
|
zatoshi: Zatoshi,
|
||||||
|
@ -140,7 +109,7 @@ class WalletTransactionEncoder: TransactionEncoder {
|
||||||
spendingKey: UnifiedSpendingKey,
|
spendingKey: UnifiedSpendingKey,
|
||||||
memoBytes: MemoBytes,
|
memoBytes: MemoBytes,
|
||||||
from accountIndex: Int
|
from accountIndex: Int
|
||||||
) throws -> EncodedTransaction {
|
) async throws -> EncodedTransaction {
|
||||||
let txId = try createShieldingSpend(
|
let txId = try createShieldingSpend(
|
||||||
spendingKey: spendingKey,
|
spendingKey: spendingKey,
|
||||||
memo: memoBytes,
|
memo: memoBytes,
|
||||||
|
@ -161,7 +130,7 @@ class WalletTransactionEncoder: TransactionEncoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createShieldingSpend(spendingKey: UnifiedSpendingKey, memo: MemoBytes, accountIndex: Int) throws -> Int {
|
func createShieldingSpend(spendingKey: String, tsk: String, memo: String?, accountIndex: Int) throws -> Int {
|
||||||
guard ensureParams(spend: self.spendParamsURL, output: self.spendParamsURL) else {
|
guard ensureParams(spend: self.spendParamsURL, output: self.spendParamsURL) else {
|
||||||
throw TransactionEncoderError.missingParams
|
throw TransactionEncoderError.missingParams
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
|
|
||||||
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
|
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
|
||||||
do {
|
do {
|
||||||
try await downloader.downloadBlockRangeAsync(range)
|
try await downloader.downloadBlockRange(range)
|
||||||
|
|
||||||
// check what was 'stored'
|
// check what was 'stored'
|
||||||
let latestHeight = try await self.storage.latestHeightAsync()
|
let latestHeight = try await self.storage.latestHeightAsync()
|
||||||
|
@ -59,33 +59,6 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSmallDownload() {
|
|
||||||
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
|
|
||||||
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
|
|
||||||
|
|
||||||
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
|
|
||||||
var latest: BlockHeight = 0
|
|
||||||
|
|
||||||
do {
|
|
||||||
latest = try downloader.lastDownloadedBlockHeight()
|
|
||||||
} catch {
|
|
||||||
XCTFail(error.localizedDescription)
|
|
||||||
}
|
|
||||||
|
|
||||||
XCTAssertEqual(latest, BlockHeight.empty())
|
|
||||||
XCTAssertNoThrow(try downloader.downloadBlockRange(range))
|
|
||||||
|
|
||||||
var currentLatest: BlockHeight = 0
|
|
||||||
do {
|
|
||||||
currentLatest = try downloader.lastDownloadedBlockHeight()
|
|
||||||
} catch {
|
|
||||||
XCTFail("latest block failed")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
XCTAssertEqual(currentLatest, upperRange )
|
|
||||||
}
|
|
||||||
|
|
||||||
func testFailure() async {
|
func testFailure() async {
|
||||||
let awfulDownloader = CompactBlockDownloader(
|
let awfulDownloader = CompactBlockDownloader(
|
||||||
service: AwfulLightWalletService(
|
service: AwfulLightWalletService(
|
||||||
|
@ -101,7 +74,7 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
|
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try await awfulDownloader.downloadBlockRangeAsync(range)
|
try await awfulDownloader.downloadBlockRange(range)
|
||||||
} catch {
|
} catch {
|
||||||
XCTAssertNotNil(error)
|
XCTAssertNotNil(error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,7 @@ class BlockStreamingTest: XCTestCase {
|
||||||
try? FileManager.default.removeItem(at: __dataDbURL())
|
try? FileManager.default.removeItem(at: __dataDbURL())
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStream() throws {
|
func testStream() async throws {
|
||||||
let expectation = XCTestExpectation(description: "blockstream expectation")
|
|
||||||
|
|
||||||
let service = LightWalletGRPCService(
|
let service = LightWalletGRPCService(
|
||||||
host: LightWalletEndpointBuilder.eccTestnet.host,
|
host: LightWalletEndpointBuilder.eccTestnet.host,
|
||||||
port: 9067,
|
port: 9067,
|
||||||
|
@ -36,23 +34,19 @@ class BlockStreamingTest: XCTestCase {
|
||||||
|
|
||||||
let startHeight = latestHeight - 100_000
|
let startHeight = latestHeight - 100_000
|
||||||
var blocks: [ZcashCompactBlock] = []
|
var blocks: [ZcashCompactBlock] = []
|
||||||
service.blockStream(startHeight: startHeight, endHeight: latestHeight) { result in
|
let stream = service.blockStream(startHeight: startHeight, endHeight: latestHeight)
|
||||||
expectation.fulfill()
|
|
||||||
switch result {
|
do {
|
||||||
case .success(let status):
|
for try await compactBlock in stream {
|
||||||
XCTAssertEqual(GRPCResult.success, status)
|
|
||||||
case .failure(let error):
|
|
||||||
XCTFail("failed with error: \(error)")
|
|
||||||
}
|
|
||||||
} handler: { compactBlock in
|
|
||||||
print("received block \(compactBlock.height)")
|
print("received block \(compactBlock.height)")
|
||||||
blocks.append(compactBlock)
|
blocks.append(compactBlock)
|
||||||
} progress: { progressReport in
|
print("progressHeight: \(compactBlock.height)")
|
||||||
print("progressHeight: \(progressReport.progressHeight)")
|
print("startHeight: \(startHeight)")
|
||||||
print("startHeight: \(progressReport.startHeight)")
|
print("targetHeight: \(latestHeight)")
|
||||||
print("targetHeight: \(progressReport.targetHeight)")
|
}
|
||||||
|
} catch {
|
||||||
|
XCTFail("failed with error: \(error)")
|
||||||
}
|
}
|
||||||
wait(for: [expectation], timeout: 1000)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStreamCancellation() async throws {
|
func testStreamCancellation() async throws {
|
||||||
|
|
|
@ -38,29 +38,6 @@ class LightWalletServiceTests: XCTestCase {
|
||||||
// wait(for: [expect], timeout: 20)
|
// wait(for: [expect], timeout: 20)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func testHundredBlocks() {
|
|
||||||
let expect = XCTestExpectation(description: self.description)
|
|
||||||
let count = 99
|
|
||||||
let lowerRange: BlockHeight = network.constants.saplingActivationHeight
|
|
||||||
let upperRange: BlockHeight = network.constants.saplingActivationHeight + count
|
|
||||||
let blockRange = lowerRange ... upperRange
|
|
||||||
|
|
||||||
service.blockRange(blockRange) { result in
|
|
||||||
expect.fulfill()
|
|
||||||
switch result {
|
|
||||||
case .failure(let error):
|
|
||||||
XCTFail("failed with error \(error)")
|
|
||||||
|
|
||||||
case .success(let blocks):
|
|
||||||
XCTAssertEqual(blocks.count, blockRange.count)
|
|
||||||
XCTAssertEqual(blocks[0].height, lowerRange)
|
|
||||||
XCTAssertEqual(blocks.last!.height, upperRange)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wait(for: [expect], timeout: 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testHundredBlocks() async throws {
|
func testHundredBlocks() async throws {
|
||||||
let count = 99
|
let count = 99
|
||||||
let lowerRange: BlockHeight = network.constants.saplingActivationHeight
|
let lowerRange: BlockHeight = network.constants.saplingActivationHeight
|
||||||
|
@ -76,19 +53,6 @@ class LightWalletServiceTests: XCTestCase {
|
||||||
XCTAssertEqual(blocks.last!.height, upperRange)
|
XCTAssertEqual(blocks.last!.height, upperRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSyncBlockRange() {
|
|
||||||
let lowerRange: BlockHeight = network.constants.saplingActivationHeight
|
|
||||||
let upperRange: BlockHeight = network.constants.saplingActivationHeight + 99
|
|
||||||
let blockRange = lowerRange ... upperRange
|
|
||||||
|
|
||||||
do {
|
|
||||||
let blocks = try service.blockRange(blockRange)
|
|
||||||
XCTAssertEqual(blocks.count, blockRange.count)
|
|
||||||
} catch {
|
|
||||||
XCTFail("\(error)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testSyncBlockRange() async throws {
|
func testSyncBlockRange() async throws {
|
||||||
let lowerRange: BlockHeight = network.constants.saplingActivationHeight
|
let lowerRange: BlockHeight = network.constants.saplingActivationHeight
|
||||||
let upperRange: BlockHeight = network.constants.saplingActivationHeight + 99
|
let upperRange: BlockHeight = network.constants.saplingActivationHeight + 99
|
||||||
|
@ -101,21 +65,6 @@ class LightWalletServiceTests: XCTestCase {
|
||||||
XCTAssertEqual(blocks.count, blockRange.count)
|
XCTAssertEqual(blocks.count, blockRange.count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testLatestBlock() {
|
|
||||||
let expect = XCTestExpectation(description: self.description)
|
|
||||||
service.latestBlockHeight { result in
|
|
||||||
expect.fulfill()
|
|
||||||
switch result {
|
|
||||||
case .failure(let e):
|
|
||||||
XCTFail("error: \(e)")
|
|
||||||
case .success(let height):
|
|
||||||
XCTAssertTrue(height > self.network.constants.saplingActivationHeight)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wait(for: [expect], timeout: 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testLatestBlock() async throws {
|
func testLatestBlock() async throws {
|
||||||
let height = try await service.latestBlockHeightAsync()
|
let height = try await service.latestBlockHeightAsync()
|
||||||
XCTAssertTrue(height > self.network.constants.saplingActivationHeight)
|
XCTAssertTrue(height > self.network.constants.saplingActivationHeight)
|
||||||
|
|
|
@ -25,14 +25,14 @@ class CompactBlockStorageTests: XCTestCase {
|
||||||
XCTAssertEqual(latestHeight, BlockHeight.empty())
|
XCTAssertEqual(latestHeight, BlockHeight.empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStoreThousandBlocks() {
|
func testStoreThousandBlocks() async {
|
||||||
let initialHeight = try! compactBlockDao.latestHeight()
|
let initialHeight = try! compactBlockDao.latestHeight()
|
||||||
let startHeight = self.network.constants.saplingActivationHeight
|
let startHeight = self.network.constants.saplingActivationHeight
|
||||||
let blockCount = Int(1_000)
|
let blockCount = Int(1_000)
|
||||||
let finalHeight = startHeight + blockCount
|
let finalHeight = startHeight + blockCount
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try TestDbBuilder.seed(db: compactBlockDao, with: startHeight...finalHeight)
|
try await TestDbBuilder.seed(db: compactBlockDao, with: startHeight...finalHeight)
|
||||||
} catch {
|
} catch {
|
||||||
XCTFail("seed faild with error: \(error)")
|
XCTFail("seed faild with error: \(error)")
|
||||||
return
|
return
|
||||||
|
@ -49,14 +49,14 @@ class CompactBlockStorageTests: XCTestCase {
|
||||||
let blockCount = Int(1_000)
|
let blockCount = Int(1_000)
|
||||||
let finalHeight = startHeight + blockCount
|
let finalHeight = startHeight + blockCount
|
||||||
|
|
||||||
try TestDbBuilder.seed(db: compactBlockDao, with: startHeight...finalHeight)
|
try await TestDbBuilder.seed(db: compactBlockDao, with: startHeight...finalHeight)
|
||||||
|
|
||||||
let latestHeight = try await compactBlockDao.latestHeightAsync()
|
let latestHeight = try await compactBlockDao.latestHeightAsync()
|
||||||
XCTAssertNotEqual(initialHeight, latestHeight)
|
XCTAssertNotEqual(initialHeight, latestHeight)
|
||||||
XCTAssertEqual(latestHeight, finalHeight)
|
XCTAssertEqual(latestHeight, finalHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStoreOneBlockFromEmpty() {
|
func testStoreOneBlockFromEmpty() async {
|
||||||
let initialHeight = try! compactBlockDao.latestHeight()
|
let initialHeight = try! compactBlockDao.latestHeight()
|
||||||
guard initialHeight == BlockHeight.empty() else {
|
guard initialHeight == BlockHeight.empty() else {
|
||||||
XCTFail("database not empty, latest height: \(initialHeight)")
|
XCTFail("database not empty, latest height: \(initialHeight)")
|
||||||
|
@ -68,7 +68,11 @@ class CompactBlockStorageTests: XCTestCase {
|
||||||
XCTFail("could not create randem block with height: \(expectedHeight)")
|
XCTFail("could not create randem block with height: \(expectedHeight)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
XCTAssertNoThrow(try compactBlockDao.write(blocks: [block]))
|
do {
|
||||||
|
try await compactBlockDao.write(blocks: [block])
|
||||||
|
} catch {
|
||||||
|
XCTFail("unexpected testStoreOneBlockFromEmpty fail")
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let result = try compactBlockDao.latestHeight()
|
let result = try compactBlockDao.latestHeight()
|
||||||
|
@ -91,27 +95,27 @@ class CompactBlockStorageTests: XCTestCase {
|
||||||
XCTFail("could not create randem block with height: \(expectedHeight)")
|
XCTFail("could not create randem block with height: \(expectedHeight)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try await compactBlockDao.writeAsync(blocks: [block])
|
try await compactBlockDao.write(blocks: [block])
|
||||||
|
|
||||||
let result = try await compactBlockDao.latestHeightAsync()
|
let result = try await compactBlockDao.latestHeightAsync()
|
||||||
XCTAssertEqual(result, expectedHeight)
|
XCTAssertEqual(result, expectedHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRewindTo() {
|
func testRewindTo() async {
|
||||||
let startHeight = self.network.constants.saplingActivationHeight
|
let startHeight = self.network.constants.saplingActivationHeight
|
||||||
let blockCount = Int(1_000)
|
let blockCount = Int(1_000)
|
||||||
let finalHeight = startHeight + blockCount
|
let finalHeight = startHeight + blockCount
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try TestDbBuilder.seed(db: compactBlockDao, with: startHeight...finalHeight)
|
try await TestDbBuilder.seed(db: compactBlockDao, with: startHeight...finalHeight)
|
||||||
} catch {
|
} catch {
|
||||||
XCTFail("seed faild with error: \(error)")
|
XCTFail("seed faild with error: \(error)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let rewindHeight = BlockHeight(finalHeight - 233)
|
let rewindHeight = BlockHeight(finalHeight - 233)
|
||||||
|
|
||||||
XCTAssertNoThrow(try compactBlockDao.rewind(to: rewindHeight))
|
|
||||||
do {
|
do {
|
||||||
|
try await compactBlockDao.rewindAsync(to: rewindHeight)
|
||||||
let latestHeight = try compactBlockDao.latestHeight()
|
let latestHeight = try compactBlockDao.latestHeight()
|
||||||
XCTAssertEqual(latestHeight, rewindHeight - 1)
|
XCTAssertEqual(latestHeight, rewindHeight - 1)
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -124,7 +128,7 @@ class CompactBlockStorageTests: XCTestCase {
|
||||||
let blockCount = Int(1_000)
|
let blockCount = Int(1_000)
|
||||||
let finalHeight = startHeight + blockCount
|
let finalHeight = startHeight + blockCount
|
||||||
|
|
||||||
try TestDbBuilder.seed(db: compactBlockDao, with: startHeight...finalHeight)
|
try await TestDbBuilder.seed(db: compactBlockDao, with: startHeight...finalHeight)
|
||||||
let rewindHeight = BlockHeight(finalHeight - 233)
|
let rewindHeight = BlockHeight(finalHeight - 233)
|
||||||
|
|
||||||
try await compactBlockDao.rewindAsync(to: rewindHeight)
|
try await compactBlockDao.rewindAsync(to: rewindHeight)
|
||||||
|
|
|
@ -58,105 +58,25 @@ class DarksideWalletService: LightWalletService {
|
||||||
self.init(endpoint: LightWalletEndpointBuilder.default)
|
self.init(endpoint: LightWalletEndpointBuilder.default)
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
|
||||||
func blockStream(
|
|
||||||
startHeight: BlockHeight,
|
|
||||||
endHeight: BlockHeight,
|
|
||||||
result: @escaping (Result<GRPCResult, LightWalletServiceError>) -> Void,
|
|
||||||
handler: @escaping (ZcashCompactBlock) -> Void,
|
|
||||||
progress: @escaping (BlockProgress) -> Void
|
|
||||||
) -> CancellableCall {
|
|
||||||
return service.blockStream(
|
|
||||||
startHeight: startHeight,
|
|
||||||
endHeight: endHeight,
|
|
||||||
result: result,
|
|
||||||
handler: handler,
|
|
||||||
progress: progress
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func blockStream(startHeight: BlockHeight, endHeight: BlockHeight) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
func blockStream(startHeight: BlockHeight, endHeight: BlockHeight) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
||||||
service.blockStream(startHeight: startHeight, endHeight: endHeight)
|
service.blockStream(startHeight: startHeight, endHeight: endHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getInfo() throws -> LightWalletdInfo {
|
|
||||||
try service.getInfo()
|
|
||||||
}
|
|
||||||
|
|
||||||
func getInfo(result: @escaping (Result<LightWalletdInfo, LightWalletServiceError>) -> Void) {
|
|
||||||
service.getInfo(result: result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func closeConnection() {
|
func closeConnection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
|
||||||
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(
|
|
||||||
for tAddress: String,
|
|
||||||
height: BlockHeight,
|
|
||||||
result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
|
|
||||||
) {
|
|
||||||
service.fetchUTXOs(for: tAddress, height: height, result: result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchUTXOs(for tAddress: String, height: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
func fetchUTXOs(for tAddress: String, height: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
||||||
service.fetchUTXOs(for: tAddress, height: height)
|
service.fetchUTXOs(for: tAddress, height: height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchUTXOs(
|
|
||||||
for tAddresses: [String],
|
|
||||||
height: BlockHeight,
|
|
||||||
result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
|
|
||||||
) {
|
|
||||||
service.fetchUTXOs(for: tAddresses, height: height, result: result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchUTXOs(for tAddresses: [String], height: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
func fetchUTXOs(for tAddresses: [String], height: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
||||||
service.fetchUTXOs(for: tAddresses, height: height)
|
service.fetchUTXOs(for: tAddresses, height: height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchTransaction(txId: Data) throws -> TransactionEntity {
|
|
||||||
try service.fetchTransaction(txId: txId)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
|
|
||||||
service.fetchTransaction(txId: txId, result: result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void) {
|
|
||||||
service.latestBlockHeight(result: result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func latestBlockHeight() throws -> BlockHeight {
|
func latestBlockHeight() throws -> BlockHeight {
|
||||||
try service.latestBlockHeight()
|
try service.latestBlockHeight()
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void) {
|
|
||||||
service.blockRange(range, result: result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func blockRange(_ range: CompactBlockRange) throws -> [ZcashCompactBlock] {
|
|
||||||
try service.blockRange(range)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Darskside lightwalletd should do a fake submission, by sending over the tx, retrieving it and including it in a new block
|
|
||||||
*/
|
|
||||||
func submit(spendTransaction: Data, result: @escaping (Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
|
|
||||||
service.submit(spendTransaction: spendTransaction, result: result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
|
|
||||||
try service.submit(spendTransaction: spendTransaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
func useDataset(_ datasetUrl: String) throws {
|
func useDataset(_ datasetUrl: String) throws {
|
||||||
try useDataset(from: datasetUrl)
|
try useDataset(from: datasetUrl)
|
||||||
}
|
}
|
||||||
|
@ -234,8 +154,8 @@ class DarksideWalletService: LightWalletService {
|
||||||
_ = try darksideService.clearAddressUtxo(Empty(), callOptions: nil).response.wait()
|
_ = try darksideService.clearAddressUtxo(Empty(), callOptions: nil).response.wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getInfoAsync() async throws -> LightWalletdInfo {
|
func getInfo() async throws -> LightWalletdInfo {
|
||||||
try service.getInfo()
|
try await service.getInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
func latestBlockHeightAsync() async throws -> BlockHeight {
|
func latestBlockHeightAsync() async throws -> BlockHeight {
|
||||||
|
@ -246,12 +166,13 @@ class DarksideWalletService: LightWalletService {
|
||||||
service.blockRange(range)
|
service.blockRange(range)
|
||||||
}
|
}
|
||||||
|
|
||||||
func submitAsync(spendTransaction: Data) async throws -> LightWalletServiceResponse {
|
/// Darskside lightwalletd should do a fake submission, by sending over the tx, retrieving it and including it in a new block
|
||||||
try service.submit(spendTransaction: spendTransaction)
|
func submit(spendTransaction: Data) async throws -> LightWalletServiceResponse {
|
||||||
|
try await service.submit(spendTransaction: spendTransaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchTransactionAsync(txId: Data) async throws -> TransactionEntity {
|
func fetchTransaction(txId: Data) async throws -> TransactionEntity {
|
||||||
try service.fetchTransaction(txId: txId)
|
try await service.fetchTransaction(txId: txId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,67 +24,17 @@ class MockLightWalletService: LightWalletService {
|
||||||
var mockLightDInfo: LightWalletdInfo?
|
var mockLightDInfo: LightWalletdInfo?
|
||||||
var queue = DispatchQueue(label: "mock service queue")
|
var queue = DispatchQueue(label: "mock service queue")
|
||||||
|
|
||||||
@discardableResult
|
|
||||||
func blockStream(
|
|
||||||
startHeight: BlockHeight,
|
|
||||||
endHeight: BlockHeight,
|
|
||||||
result: @escaping (Result<GRPCResult, LightWalletServiceError>) -> Void,
|
|
||||||
handler: @escaping (ZcashCompactBlock) -> Void,
|
|
||||||
progress: @escaping (BlockProgress) -> Void
|
|
||||||
) -> CancellableCall {
|
|
||||||
return MockCancellable()
|
|
||||||
}
|
|
||||||
|
|
||||||
func blockStream(startHeight: BlockHeight, endHeight: BlockHeight) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
func blockStream(startHeight: BlockHeight, endHeight: BlockHeight) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
||||||
AsyncThrowingStream { _ in }
|
AsyncThrowingStream { _ in }
|
||||||
}
|
}
|
||||||
|
|
||||||
func getInfo() throws -> LightWalletdInfo {
|
|
||||||
guard let info = mockLightDInfo else {
|
|
||||||
throw LightWalletServiceError.generalError(message: "Not Implemented")
|
|
||||||
}
|
|
||||||
return info
|
|
||||||
}
|
|
||||||
|
|
||||||
func getInfo(result: @escaping (Result<LightWalletdInfo, LightWalletServiceError>) -> Void) {
|
|
||||||
queue.async { [weak self] in
|
|
||||||
guard let info = self?.mockLightDInfo else {
|
|
||||||
result(.failure(LightWalletServiceError.generalError(message: "Not Implemented")))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
result(.success(info))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func closeConnection() {
|
func closeConnection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
|
||||||
[]
|
|
||||||
}
|
|
||||||
|
|
||||||
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 tAddress: String, height: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
func fetchUTXOs(for tAddress: String, height: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
||||||
AsyncThrowingStream { _ in }
|
AsyncThrowingStream { _ in }
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchUTXOs(
|
|
||||||
for tAddresses: [String],
|
|
||||||
height: BlockHeight,
|
|
||||||
result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchUTXOs(for tAddresses: [String], height: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
func fetchUTXOs(for tAddresses: [String], height: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
||||||
AsyncThrowingStream { _ in }
|
AsyncThrowingStream { _ in }
|
||||||
}
|
}
|
||||||
|
@ -98,42 +48,11 @@ class MockLightWalletService: LightWalletService {
|
||||||
self.service = service
|
self.service = service
|
||||||
}
|
}
|
||||||
|
|
||||||
func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void) {
|
|
||||||
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
|
|
||||||
result(.success(self.latestHeight))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func latestBlockHeight() throws -> BlockHeight {
|
func latestBlockHeight() throws -> BlockHeight {
|
||||||
return self.latestHeight
|
return self.latestHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void) {
|
func getInfo() async throws -> LightWalletdInfo {
|
||||||
self.service.blockRange(range, result: result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func blockRange(_ range: CompactBlockRange) throws -> [ZcashCompactBlock] {
|
|
||||||
try self.service.blockRange(range)
|
|
||||||
}
|
|
||||||
|
|
||||||
func submit(spendTransaction: Data, result: @escaping (Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
|
|
||||||
DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + 1) {
|
|
||||||
result(.success(LightWalletServiceMockResponse(errorCode: 0, errorMessage: "", unknownFields: UnknownStorage())))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
|
|
||||||
return LightWalletServiceMockResponse(errorCode: 0, errorMessage: "", unknownFields: UnknownStorage())
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchTransaction(txId: Data) throws -> TransactionEntity {
|
|
||||||
Transaction(id: 1, transactionId: Data(), created: "Today", transactionIndex: 1, expiryHeight: -1, minedHeight: -1, raw: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func getInfoAsync() async throws -> LightWalletdInfo {
|
|
||||||
guard let info = mockLightDInfo else {
|
guard let info = mockLightDInfo else {
|
||||||
throw LightWalletServiceError.generalError(message: "Not Implemented")
|
throw LightWalletServiceError.generalError(message: "Not Implemented")
|
||||||
}
|
}
|
||||||
|
@ -148,19 +67,11 @@ class MockLightWalletService: LightWalletService {
|
||||||
service.blockRange(range)
|
service.blockRange(range)
|
||||||
}
|
}
|
||||||
|
|
||||||
func submitAsync(spendTransaction: Data) async throws -> LightWalletServiceResponse {
|
func submit(spendTransaction: Data) async throws -> LightWalletServiceResponse {
|
||||||
LightWalletServiceMockResponse(errorCode: 0, errorMessage: "", unknownFields: UnknownStorage())
|
LightWalletServiceMockResponse(errorCode: 0, errorMessage: "", unknownFields: UnknownStorage())
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchTransactionAsync(txId: Data) async throws -> TransactionEntity {
|
func fetchTransaction(txId: Data) async throws -> TransactionEntity {
|
||||||
Transaction(id: 1, transactionId: Data(), created: "Today", transactionIndex: 1, expiryHeight: -1, minedHeight: -1, raw: nil)
|
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] {
|
|
||||||
[]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ class ZcashConsoleFakeStorage: CompactBlockRepository {
|
||||||
latestBlockHeight
|
latestBlockHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeAsync(blocks: [ZcashCompactBlock]) async throws {
|
func write(blocks: [ZcashCompactBlock]) async throws {
|
||||||
fakeSave(blocks: blocks)
|
fakeSave(blocks: blocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,10 +26,6 @@ class ZcashConsoleFakeStorage: CompactBlockRepository {
|
||||||
return self.latestBlockHeight
|
return self.latestBlockHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
func write(blocks: [ZcashCompactBlock]) throws {
|
|
||||||
fakeSave(blocks: blocks)
|
|
||||||
}
|
|
||||||
|
|
||||||
func rewind(to height: BlockHeight) throws {
|
func rewind(to height: BlockHeight) throws {
|
||||||
fakeRewind(to: height)
|
fakeRewind(to: height)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,52 +17,26 @@ class AwfulLightWalletService: MockLightWalletService {
|
||||||
throw LightWalletServiceError.criticalError
|
throw LightWalletServiceError.criticalError
|
||||||
}
|
}
|
||||||
|
|
||||||
override func blockRange(_ range: CompactBlockRange) throws -> [ZcashCompactBlock] {
|
override func latestBlockHeightAsync() async throws -> BlockHeight {
|
||||||
throw LightWalletServiceError.invalidBlock
|
throw LightWalletServiceError.invalidBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
override func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void) {
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
|
||||||
result(.failure(LightWalletServiceError.invalidBlock))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void) {
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
|
||||||
result(.failure(LightWalletServiceError.invalidBlock))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func blockRange(_ range: CompactBlockRange) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
override func blockRange(_ range: CompactBlockRange) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
||||||
AsyncThrowingStream { continuation in continuation.finish(throwing: LightWalletServiceError.invalidBlock) }
|
AsyncThrowingStream { continuation in continuation.finish(throwing: LightWalletServiceError.invalidBlock) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
|
/// Submits a raw transaction over lightwalletd.
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
override func submit(spendTransaction: Data) async throws -> LightWalletServiceResponse {
|
||||||
result(.failure(LightWalletServiceError.invalidBlock))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Submits a raw transaction over lightwalletd. Blocking
|
|
||||||
*/
|
|
||||||
override func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
|
|
||||||
throw LightWalletServiceError.invalidBlock
|
throw LightWalletServiceError.invalidBlock
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SlightlyBadLightWalletService: MockLightWalletService {
|
extension LightWalletServiceMockResponse: Error { }
|
||||||
override func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
|
||||||
result(.success(LightWalletServiceMockResponse.error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
class SlightlyBadLightWalletService: MockLightWalletService {
|
||||||
Submits a raw transaction over lightwalletd. Blocking
|
/// Submits a raw transaction over lightwalletd.
|
||||||
*/
|
override func submit(spendTransaction: Data) async throws -> LightWalletServiceResponse {
|
||||||
override func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
|
throw LightWalletServiceMockResponse.error
|
||||||
LightWalletServiceMockResponse.error
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,12 +96,12 @@ class TestDbBuilder {
|
||||||
return ReceivedNotesSQLDAO(dbProvider: provider)
|
return ReceivedNotesSQLDAO(dbProvider: provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func seed(db: CompactBlockRepository, with blockRange: CompactBlockRange) throws {
|
static func seed(db: CompactBlockRepository, with blockRange: CompactBlockRange) async throws {
|
||||||
guard let blocks = StubBlockCreator.createBlockRange(blockRange) else {
|
guard let blocks = StubBlockCreator.createBlockRange(blockRange) else {
|
||||||
throw TestBuilderError.generalError
|
throw TestBuilderError.generalError
|
||||||
}
|
}
|
||||||
|
|
||||||
try db.write(blocks: blocks)
|
try await db.write(blocks: blocks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import GRPC
|
||||||
import ZcashLightClientKit
|
import ZcashLightClientKit
|
||||||
import XCTest
|
import XCTest
|
||||||
import NIO
|
import NIO
|
||||||
|
import NIOTransportServices
|
||||||
|
|
||||||
enum Environment {
|
enum Environment {
|
||||||
static let lightwalletdKey = "LIGHTWALLETD_ADDRESS"
|
static let lightwalletdKey = "LIGHTWALLETD_ADDRESS"
|
||||||
|
@ -40,8 +41,8 @@ class ChannelProvider {
|
||||||
let endpoint = LightWalletEndpointBuilder.default
|
let endpoint = LightWalletEndpointBuilder.default
|
||||||
|
|
||||||
let connectionBuilder = secure ?
|
let connectionBuilder = secure ?
|
||||||
ClientConnection.usingPlatformAppropriateTLS(for: MultiThreadedEventLoopGroup(numberOfThreads: 1)) :
|
ClientConnection.usingPlatformAppropriateTLS(for: NIOTSEventLoopGroup(loopCount: 1, defaultQoS: .default)) :
|
||||||
ClientConnection.insecure(group: MultiThreadedEventLoopGroup(numberOfThreads: 1))
|
ClientConnection.insecure(group: NIOTSEventLoopGroup(loopCount: 1, defaultQoS: .default))
|
||||||
|
|
||||||
let channel = connectionBuilder
|
let channel = connectionBuilder
|
||||||
.withKeepalive(
|
.withKeepalive(
|
||||||
|
|
Loading…
Reference in New Issue