- await/async APIs provided - async throws unit tests using new API implemented [464] CompactBlockStorage To async/await (494) - removed deprecated closure APIs - upgraded use of the async APIs - tests updated
This commit is contained in:
parent
f1a570bbc2
commit
742e6bd8ec
|
@ -85,39 +85,28 @@ extension CompactBlockStorage: CompactBlockRepository {
|
|||
try latestBlockHeight()
|
||||
}
|
||||
|
||||
func latestHeight(result: @escaping (Swift.Result<BlockHeight, Error>) -> Void) {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
do {
|
||||
result(.success(try self.latestBlockHeight()))
|
||||
} catch {
|
||||
result(.failure(error))
|
||||
}
|
||||
func latestHeightAsync() async throws -> BlockHeight {
|
||||
let task = Task(priority: .userInitiated) {
|
||||
try latestBlockHeight()
|
||||
}
|
||||
return try await task.value
|
||||
}
|
||||
|
||||
|
||||
func write(blocks: [ZcashCompactBlock]) throws {
|
||||
try insert(blocks)
|
||||
}
|
||||
|
||||
func write(blocks: [ZcashCompactBlock], completion: ((Error?) -> Void)?) {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
do {
|
||||
try self.insert(blocks)
|
||||
completion?(nil)
|
||||
} catch {
|
||||
completion?(error)
|
||||
}
|
||||
func writeAsync(blocks: [ZcashCompactBlock]) async throws {
|
||||
let task = Task(priority: .userInitiated) {
|
||||
try insert(blocks)
|
||||
}
|
||||
try await task.value
|
||||
}
|
||||
|
||||
func rewind(to height: BlockHeight, completion: ((Error?) -> Void)?) {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
do {
|
||||
try self.rewind(to: height)
|
||||
completion?(nil)
|
||||
} catch {
|
||||
completion?(error)
|
||||
}
|
||||
|
||||
func rewindAsync(to height: BlockHeight) async throws {
|
||||
let task = Task(priority: .userInitiated) {
|
||||
try rewind(to: height)
|
||||
}
|
||||
try await task.value
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,13 @@ enum CompactBlockDownloadError: Error {
|
|||
Represents what a compact block downloaded should provide to its clients
|
||||
*/
|
||||
public protocol CompactBlockDownloading {
|
||||
|
||||
/**
|
||||
Downloads and stores the given block range.
|
||||
Blocking
|
||||
*/
|
||||
func downloadBlockRange(_ range: CompactBlockRange) throws
|
||||
|
||||
/**
|
||||
Downloads and stores the given block range.
|
||||
Non-Blocking
|
||||
|
@ -46,12 +53,6 @@ public protocol CompactBlockDownloading {
|
|||
*/
|
||||
func latestBlockHeight(result: @escaping (Result<BlockHeight, Error>) -> Void)
|
||||
|
||||
/**
|
||||
Downloads and stores the given block range.
|
||||
Blocking
|
||||
*/
|
||||
func downloadBlockRange(_ range: CompactBlockRange) throws
|
||||
|
||||
/**
|
||||
Restore the download progress up to the given height.
|
||||
*/
|
||||
|
@ -176,18 +177,17 @@ extension CompactBlockDownloader: CompactBlockDownloading {
|
|||
_ heightRange: CompactBlockRange,
|
||||
completion: @escaping (Error?) -> Void
|
||||
) {
|
||||
lightwalletService.blockRange(heightRange) { [weak self] result in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
completion(error)
|
||||
case .success(let compactBlocks):
|
||||
self.storage.write(blocks: compactBlocks) { storeError in
|
||||
completion(storeError)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -198,20 +198,25 @@ extension CompactBlockDownloader: CompactBlockDownloading {
|
|||
}
|
||||
|
||||
func rewind(to height: BlockHeight, completion: @escaping (Error?) -> Void) {
|
||||
storage.rewind(to: height) { e in
|
||||
completion(e)
|
||||
Task {
|
||||
do {
|
||||
try await storage.rewindAsync(to: height)
|
||||
completion(nil)
|
||||
} catch {
|
||||
completion(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func lastDownloadedBlockHeight(result: @escaping (Result<BlockHeight, Error>) -> Void) {
|
||||
storage.latestHeight { heightResult in
|
||||
switch heightResult {
|
||||
case .failure(let e):
|
||||
result(.failure(CompactBlockDownloadError.generalError(error: e)))
|
||||
return
|
||||
case .success(let height):
|
||||
result(.success(height))
|
||||
Task {
|
||||
do {
|
||||
let latestHeight = try await storage.latestHeightAsync()
|
||||
result(.success(latestHeight))
|
||||
} catch {
|
||||
result(.failure(CompactBlockDownloadError.generalError(error: error)))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,11 +28,9 @@ protocol CompactBlockRepository {
|
|||
/**
|
||||
Gets the highest block that is currently stored.
|
||||
Non-Blocking
|
||||
|
||||
- Parameter result: closure resulting on either the latest height or an error
|
||||
*/
|
||||
func latestHeight(result: @escaping (Result<BlockHeight, Error>) -> Void)
|
||||
|
||||
func latestHeightAsync() async throws -> BlockHeight
|
||||
|
||||
/**
|
||||
Write the given blocks to this store, which may be anything from an in-memory cache to a DB.
|
||||
Blocking
|
||||
|
@ -46,10 +44,9 @@ protocol CompactBlockRepository {
|
|||
Non-Blocking
|
||||
- Parameters:
|
||||
- Parameter blocks: array of blocks to be written to storage
|
||||
- Parameter completion: a closure that will be called after storing the blocks
|
||||
*/
|
||||
func write(blocks: [ZcashCompactBlock], completion: ((Error?) -> Void)?)
|
||||
|
||||
func writeAsync(blocks: [ZcashCompactBlock]) async throws
|
||||
|
||||
/**
|
||||
Remove every block above and including the given height.
|
||||
|
||||
|
@ -66,10 +63,7 @@ protocol CompactBlockRepository {
|
|||
After this operation, the data store will look the same as one that has not yet stored the given block height.
|
||||
Meaning, if max height is 100 block and rewindTo(50) is called, then the highest block remaining will be 49.
|
||||
|
||||
- Parameters:
|
||||
- Parameter height: the height to rewind to
|
||||
- Parameter completion: a closure that will be called after storing the blocks
|
||||
|
||||
*/
|
||||
func rewind(to height: BlockHeight, completion: ((Error?) -> Void)?)
|
||||
func rewindAsync(to height: BlockHeight) async throws
|
||||
}
|
||||
|
|
|
@ -51,15 +51,20 @@ class BlockDownloaderTests: XCTestCase {
|
|||
expect.fulfill()
|
||||
XCTAssertNil(error)
|
||||
|
||||
// check what was 'stored'
|
||||
self.storage.latestHeight { result in
|
||||
expect.fulfill()
|
||||
|
||||
XCTAssertTrue(self.validate(result: result, against: upperRange))
|
||||
|
||||
self.downloader.lastDownloadedBlockHeight { resultHeight in
|
||||
Task {
|
||||
do {
|
||||
// check what was 'stored'
|
||||
let latestHeight = try await self.storage.latestHeightAsync()
|
||||
expect.fulfill()
|
||||
XCTAssertTrue(self.validate(result: resultHeight, against: upperRange))
|
||||
|
||||
XCTAssertEqual(latestHeight, upperRange)
|
||||
|
||||
self.downloader.lastDownloadedBlockHeight { resultHeight in
|
||||
expect.fulfill()
|
||||
XCTAssertTrue(self.validate(result: resultHeight, against: upperRange))
|
||||
}
|
||||
} catch {
|
||||
XCTFail("testSmallDownloadAsync() shouldn't fail")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,12 @@ class CompactBlockStorageTests: XCTestCase {
|
|||
func testEmptyStorage() {
|
||||
XCTAssertEqual(try! compactBlockDao.latestHeight(), BlockHeight.empty())
|
||||
}
|
||||
|
||||
|
||||
func testEmptyStorageAsync() async throws {
|
||||
let latestHeight = try await compactBlockDao.latestHeightAsync()
|
||||
XCTAssertEqual(latestHeight, BlockHeight.empty())
|
||||
}
|
||||
|
||||
func testStoreThousandBlocks() {
|
||||
let initialHeight = try! compactBlockDao.latestHeight()
|
||||
let startHeight = self.network.constants.saplingActivationHeight
|
||||
|
@ -38,6 +43,19 @@ class CompactBlockStorageTests: XCTestCase {
|
|||
XCTAssertEqual(latestHeight, finalHeight)
|
||||
}
|
||||
|
||||
func testStoreThousandBlocksAsync() async throws {
|
||||
let initialHeight = try! compactBlockDao.latestHeight()
|
||||
let startHeight = self.network.constants.saplingActivationHeight
|
||||
let blockCount = Int(1_000)
|
||||
let finalHeight = startHeight + blockCount
|
||||
|
||||
try TestDbBuilder.seed(db: compactBlockDao, with: startHeight...finalHeight)
|
||||
|
||||
let latestHeight = try await compactBlockDao.latestHeightAsync()
|
||||
XCTAssertNotEqual(initialHeight, latestHeight)
|
||||
XCTAssertEqual(latestHeight, finalHeight)
|
||||
}
|
||||
|
||||
func testStoreOneBlockFromEmpty() {
|
||||
let initialHeight = try! compactBlockDao.latestHeight()
|
||||
guard initialHeight == BlockHeight.empty() else {
|
||||
|
@ -61,6 +79,24 @@ class CompactBlockStorageTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
func testStoreOneBlockFromEmptyAsync() async throws {
|
||||
let initialHeight = try await compactBlockDao.latestHeightAsync()
|
||||
guard initialHeight == BlockHeight.empty() else {
|
||||
XCTFail("database not empty, latest height: \(initialHeight)")
|
||||
return
|
||||
}
|
||||
|
||||
let expectedHeight = BlockHeight(123_456)
|
||||
guard let block = StubBlockCreator.createRandomDataBlock(with: expectedHeight) else {
|
||||
XCTFail("could not create randem block with height: \(expectedHeight)")
|
||||
return
|
||||
}
|
||||
try await compactBlockDao.writeAsync(blocks: [block])
|
||||
|
||||
let result = try await compactBlockDao.latestHeightAsync()
|
||||
XCTAssertEqual(result, expectedHeight)
|
||||
}
|
||||
|
||||
func testRewindTo() {
|
||||
let startHeight = self.network.constants.saplingActivationHeight
|
||||
let blockCount = Int(1_000)
|
||||
|
@ -82,4 +118,17 @@ class CompactBlockStorageTests: XCTestCase {
|
|||
XCTFail("Rewind latest block failed with error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func testRewindToAsync() async throws {
|
||||
let startHeight = self.network.constants.saplingActivationHeight
|
||||
let blockCount = Int(1_000)
|
||||
let finalHeight = startHeight + blockCount
|
||||
|
||||
try TestDbBuilder.seed(db: compactBlockDao, with: startHeight...finalHeight)
|
||||
let rewindHeight = BlockHeight(finalHeight - 233)
|
||||
|
||||
try await compactBlockDao.rewindAsync(to: rewindHeight)
|
||||
let latestHeight = try await compactBlockDao.latestHeightAsync()
|
||||
XCTAssertEqual(latestHeight, rewindHeight - 1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,18 @@ import Foundation
|
|||
@testable import ZcashLightClientKit
|
||||
|
||||
class ZcashConsoleFakeStorage: CompactBlockRepository {
|
||||
func latestHeightAsync() async throws -> BlockHeight {
|
||||
latestBlockHeight
|
||||
}
|
||||
|
||||
func writeAsync(blocks: [ZcashCompactBlock]) async throws {
|
||||
fakeSave(blocks: blocks)
|
||||
}
|
||||
|
||||
func rewindAsync(to height: BlockHeight) async throws {
|
||||
fakeRewind(to: height)
|
||||
}
|
||||
|
||||
func latestHeight() throws -> Int {
|
||||
return self.latestBlockHeight
|
||||
}
|
||||
|
@ -29,12 +41,6 @@ class ZcashConsoleFakeStorage: CompactBlockRepository {
|
|||
self.latestBlockHeight = latestBlockHeight
|
||||
}
|
||||
|
||||
func latestHeight(result: @escaping (Result<BlockHeight, Error>) -> Void) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
||||
result(.success(self.latestBlockHeight))
|
||||
}
|
||||
}
|
||||
|
||||
private func fakeSave(blocks: [ZcashCompactBlock]) {
|
||||
blocks.forEach {
|
||||
LoggerProxy.debug("saving block \($0)")
|
||||
|
@ -42,20 +48,6 @@ class ZcashConsoleFakeStorage: CompactBlockRepository {
|
|||
}
|
||||
}
|
||||
|
||||
func write(blocks: [ZcashCompactBlock], completion: ((Error?) -> Void)?) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
||||
self.fakeSave(blocks: blocks)
|
||||
completion?(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func rewind(to height: BlockHeight, completion: ((Error?) -> Void)?) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
||||
self.fakeRewind(to: height)
|
||||
completion?(nil)
|
||||
}
|
||||
}
|
||||
|
||||
private func fakeRewind(to height: BlockHeight) {
|
||||
LoggerProxy.debug("rewind to \(height)")
|
||||
self.latestBlockHeight = min(self.latestBlockHeight, height)
|
||||
|
|
|
@ -33,6 +33,10 @@ class AwfulLightWalletService: MockLightWalletService {
|
|||
}
|
||||
}
|
||||
|
||||
override func blockRange(_ range: CompactBlockRange) -> AsyncThrowingStream<ZcashCompactBlock, Error> {
|
||||
AsyncThrowingStream { continuation in continuation.finish(throwing: LightWalletServiceError.invalidBlock) }
|
||||
}
|
||||
|
||||
override func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
result(.failure(LightWalletServiceError.invalidBlock))
|
||||
|
|
Loading…
Reference in New Issue