Closes #465 - CompactBlockDownloading closures removed - CompactBlockDownloading new async API provided
This commit is contained in:
parent
30bfa6c633
commit
16d1948b5b
|
@ -27,49 +27,44 @@ public protocol CompactBlockDownloading {
|
||||||
Downloads and stores the given block range.
|
Downloads and stores the given block range.
|
||||||
Non-Blocking
|
Non-Blocking
|
||||||
*/
|
*/
|
||||||
func downloadBlockRange(
|
func downloadBlockRangeAsync(_ heightRange: CompactBlockRange) async throws
|
||||||
_ 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)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Restore the download progress up to the given height.
|
Restore the download progress up to the given height.
|
||||||
*/
|
*/
|
||||||
func rewind(to height: BlockHeight) throws
|
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.
|
Returns the height of the latest compact block stored locally.
|
||||||
BlockHeight.empty() if no blocks are stored yet
|
BlockHeight.empty() if no blocks are stored yet
|
||||||
Blocking
|
Blocking
|
||||||
*/
|
*/
|
||||||
func lastDownloadedBlockHeight() throws -> BlockHeight
|
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
|
Returns the latest block height
|
||||||
Blocking
|
Blocking
|
||||||
*/
|
*/
|
||||||
func latestBlockHeight() throws -> BlockHeight
|
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
|
Gets the transaction for the Id given
|
||||||
|
@ -82,17 +77,30 @@ 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
|
||||||
- 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]
|
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, 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) 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()
|
func closeConnection()
|
||||||
}
|
}
|
||||||
|
@ -138,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] {
|
func fetchUnspentTransactionOutputs(tAddress: String, startHeight: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
||||||
try lightwalletService.fetchUTXOs(for: tAddress, height: startHeight)
|
try lightwalletService.fetchUTXOs(for: tAddress, height: startHeight)
|
||||||
|
@ -154,72 +166,54 @@ extension CompactBlockDownloader: CompactBlockDownloading {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func latestBlockHeight(result: @escaping (Result<BlockHeight, Error>) -> Void) {
|
func fetchUnspentTransactionOutputs(tAddress: String, startHeight: BlockHeight) -> AsyncThrowingStream<UnspentTransactionOutputEntity, Error> {
|
||||||
lightwalletService.latestBlockHeight { fetchResult in
|
lightwalletService.fetchUTXOs(for: tAddress, height: startHeight)
|
||||||
switch fetchResult {
|
}
|
||||||
case .failure(let error):
|
|
||||||
result(.failure(error))
|
func latestBlockHeightAsync() async throws -> BlockHeight {
|
||||||
case .success(let height):
|
try await lightwalletService.latestBlockHeightAsync()
|
||||||
result(.success(height))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func latestBlockHeight() throws -> BlockHeight {
|
func latestBlockHeight() throws -> BlockHeight {
|
||||||
try lightwalletService.latestBlockHeight()
|
try lightwalletService.latestBlockHeight()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
Downloads and stores the given block range.
|
|
||||||
Non-Blocking
|
|
||||||
*/
|
|
||||||
func downloadBlockRange(
|
|
||||||
_ heightRange: CompactBlockRange,
|
|
||||||
completion: @escaping (Error?) -> Void
|
|
||||||
) {
|
|
||||||
let stream: AsyncThrowingStream<ZcashCompactBlock, Error> = lightwalletService.blockRange(heightRange)
|
|
||||||
Task {
|
|
||||||
do {
|
|
||||||
var compactBlocks: [ZcashCompactBlock] = []
|
|
||||||
for try await compactBlock in stream {
|
|
||||||
compactBlocks.append(compactBlock)
|
|
||||||
}
|
|
||||||
try await self.storage.writeAsync(blocks: compactBlocks)
|
|
||||||
completion(nil)
|
|
||||||
} catch {
|
|
||||||
completion(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func downloadBlockRange(_ range: CompactBlockRange) throws {
|
func downloadBlockRange(_ range: CompactBlockRange) throws {
|
||||||
let blocks = try lightwalletService.blockRange(range)
|
let blocks = try lightwalletService.blockRange(range)
|
||||||
try storage.write(blocks: blocks)
|
try storage.write(blocks: blocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
func rewind(to height: BlockHeight, completion: @escaping (Error?) -> Void) {
|
func downloadBlockRangeAsync( _ heightRange: CompactBlockRange) async throws {
|
||||||
Task {
|
let stream: AsyncThrowingStream<ZcashCompactBlock, Error> = lightwalletService.blockRange(heightRange)
|
||||||
do {
|
do {
|
||||||
try await storage.rewindAsync(to: height)
|
var compactBlocks: [ZcashCompactBlock] = []
|
||||||
completion(nil)
|
for try await compactBlock in stream {
|
||||||
} catch {
|
compactBlocks.append(compactBlock)
|
||||||
completion(error)
|
|
||||||
}
|
}
|
||||||
|
try await self.storage.writeAsync(blocks: compactBlocks)
|
||||||
|
} catch {
|
||||||
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func lastDownloadedBlockHeight(result: @escaping (Result<BlockHeight, Error>) -> Void) {
|
func rewindAsync(to height: BlockHeight) async throws {
|
||||||
Task {
|
do {
|
||||||
do {
|
try await storage.rewindAsync(to: height)
|
||||||
let latestHeight = try await storage.latestHeightAsync()
|
} catch {
|
||||||
result(.success(latestHeight))
|
throw error
|
||||||
} catch {
|
|
||||||
result(.failure(CompactBlockDownloadError.generalError(error: 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 {
|
func rewind(to height: BlockHeight) throws {
|
||||||
try self.storage.rewind(to: height)
|
try self.storage.rewind(to: height)
|
||||||
}
|
}
|
||||||
|
@ -232,14 +226,7 @@ extension CompactBlockDownloader: CompactBlockDownloading {
|
||||||
try lightwalletService.fetchTransaction(txId: txId)
|
try lightwalletService.fetchTransaction(txId: txId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, Error>) -> Void) {
|
func fetchTransactionAsync(txId: Data) async throws -> TransactionEntity {
|
||||||
lightwalletService.fetchTransaction(txId: txId) { txResult in
|
try await lightwalletService.fetchTransactionAsync(txId: txId)
|
||||||
switch txResult {
|
|
||||||
case .failure(let error):
|
|
||||||
result(.failure(error))
|
|
||||||
case .success(let transaction):
|
|
||||||
result(.success(transaction))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,9 @@ class CompactBlockDownloadOperation: ZcashOperation {
|
||||||
|
|
||||||
private var downloader: CompactBlockDownloading
|
private var downloader: CompactBlockDownloading
|
||||||
private var range: CompactBlockRange
|
private var range: CompactBlockRange
|
||||||
|
private var cancelableTask: Task<Void, Error>?
|
||||||
|
private var done = false
|
||||||
|
|
||||||
required init(downloader: CompactBlockDownloading, range: CompactBlockRange) {
|
required init(downloader: CompactBlockDownloading, range: CompactBlockRange) {
|
||||||
self.range = range
|
self.range = range
|
||||||
self.downloader = downloader
|
self.downloader = downloader
|
||||||
|
@ -28,12 +30,29 @@ class CompactBlockDownloadOperation: ZcashOperation {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.startedHandler?()
|
self.startedHandler?()
|
||||||
do {
|
|
||||||
try downloader.downloadBlockRange(range)
|
cancelableTask = Task {
|
||||||
} catch {
|
do {
|
||||||
self.error = error
|
try await downloader.downloadBlockRangeAsync(range)
|
||||||
self.fail()
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,9 @@ class FetchUnspentTxOutputsOperation: ZcashOperation {
|
||||||
throw FetchUTXOError.clearingFailed(error)
|
throw FetchUTXOError.clearingFailed(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
let utxos = try downloader.fetchUnspentTransactionOutputs(tAddresses: tAddresses, startHeight: startHeight)
|
// TODO: will be replaced by new async API, issue 474
|
||||||
|
// https://github.com/zcash/ZcashLightClientKit/issues/474
|
||||||
|
let utxos: [UnspentTransactionOutputEntity] = try downloader.fetchUnspentTransactionOutputs(tAddresses: tAddresses, startHeight: startHeight)
|
||||||
|
|
||||||
let result = storeUTXOs(utxos, in: dataDb)
|
let result = storeUTXOs(utxos, in: dataDb)
|
||||||
|
|
||||||
|
|
|
@ -631,7 +631,14 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func latestHeight(result: @escaping (Result<BlockHeight, Error>) -> Void) {
|
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 {
|
public func latestHeight() throws -> BlockHeight {
|
||||||
|
|
|
@ -40,36 +40,23 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
try? FileManager.default.removeItem(at: cacheDB)
|
try? FileManager.default.removeItem(at: cacheDB)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSmallDownloadAsync() {
|
func testSmallDownloadAsync() async {
|
||||||
let expect = XCTestExpectation(description: self.description)
|
|
||||||
expect.expectedFulfillmentCount = 3
|
|
||||||
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
|
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
|
||||||
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
|
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
|
||||||
|
|
||||||
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
|
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
|
||||||
downloader.downloadBlockRange(range) { error in
|
do {
|
||||||
expect.fulfill()
|
try await downloader.downloadBlockRangeAsync(range)
|
||||||
XCTAssertNil(error)
|
|
||||||
|
|
||||||
Task {
|
// check what was 'stored'
|
||||||
do {
|
let latestHeight = try await self.storage.latestHeightAsync()
|
||||||
// check what was 'stored'
|
XCTAssertEqual(latestHeight, upperRange)
|
||||||
let latestHeight = try await self.storage.latestHeightAsync()
|
|
||||||
expect.fulfill()
|
let resultHeight = try await self.downloader.lastDownloadedBlockHeightAsync()
|
||||||
|
XCTAssertEqual(resultHeight, upperRange)
|
||||||
XCTAssertEqual(latestHeight, upperRange)
|
} catch {
|
||||||
|
XCTFail("testSmallDownloadAsync() shouldn't fail")
|
||||||
self.downloader.lastDownloadedBlockHeight { resultHeight in
|
|
||||||
expect.fulfill()
|
|
||||||
XCTAssertTrue(self.validate(result: resultHeight, against: upperRange))
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
XCTFail("testSmallDownloadAsync() shouldn't fail")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wait(for: [expect], timeout: 2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSmallDownload() {
|
func testSmallDownload() {
|
||||||
|
@ -99,7 +86,7 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
XCTAssertEqual(currentLatest, upperRange )
|
XCTAssertEqual(currentLatest, upperRange )
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFailure() {
|
func testFailure() async {
|
||||||
let awfulDownloader = CompactBlockDownloader(
|
let awfulDownloader = CompactBlockDownloader(
|
||||||
service: AwfulLightWalletService(
|
service: AwfulLightWalletService(
|
||||||
latestBlockHeight: self.network.constants.saplingActivationHeight + 1000,
|
latestBlockHeight: self.network.constants.saplingActivationHeight + 1000,
|
||||||
|
@ -108,18 +95,16 @@ class BlockDownloaderTests: XCTestCase {
|
||||||
storage: ZcashConsoleFakeStorage()
|
storage: ZcashConsoleFakeStorage()
|
||||||
)
|
)
|
||||||
|
|
||||||
let expect = XCTestExpectation(description: self.description)
|
|
||||||
expect.expectedFulfillmentCount = 1
|
|
||||||
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
|
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
|
||||||
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
|
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
|
||||||
|
|
||||||
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
|
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
|
||||||
|
|
||||||
awfulDownloader.downloadBlockRange(range) { error in
|
do {
|
||||||
expect.fulfill()
|
try await awfulDownloader.downloadBlockRangeAsync(range)
|
||||||
|
} catch {
|
||||||
XCTAssertNotNil(error)
|
XCTAssertNotNil(error)
|
||||||
}
|
}
|
||||||
wait(for: [expect], timeout: 2)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue