SwiftLint Enabled on Test Folder

This commit is contained in:
Adam Stener 2021-09-23 08:26:41 -05:00
parent db5f02dbf9
commit 78b1f937ba
41 changed files with 3068 additions and 2246 deletions

View File

@ -3,12 +3,14 @@
excluded:
- Pods
- ZcashLightClientKitTests
- ZcashLightClientKit/Service/ProtoBuf
- ZcashLightClientKitTests/proto
- ZcashLightClientKitTests/Constants.generated.swift
included:
- Example/ZcashLightClientSample/ZcashLIghtClientSample
- ZcashLightClientKit
- ZcashLightClientKitTests
disabled_rules:
- notification_center_detachment

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -8,27 +8,45 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable force_try type_body_length
class BlockBatchValidationTests: XCTestCase {
var queue: OperationQueue = {
let q = OperationQueue()
q.name = "Test Queue"
q.maxConcurrentOperationCount = 1
return q
let queue = OperationQueue()
queue.name = "Test Queue"
queue.maxConcurrentOperationCount = 1
return queue
}()
override func setUpWithError() throws {
override func setUp() {
// Put setup code here. This method is called before the invocation of each test method in the class.
super.setUp()
}
override func tearDownWithError() throws {
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testBranchIdFailure() throws {
let network = ZcashNetworkBuilder.network(for: .mainnet)
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let service = MockLightWalletService(
latestBlockHeight: 1210000,
service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)
)
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.saplingActivationHeight, network: network)
let config = CompactBlockProcessor.Configuration(
cacheDb: try! __cacheDbURL(),
dataDb: try! __dataDbURL(),
downloadBatchSize: 100,
retries: 5,
maxBackoffInterval: 10,
rewindDistance: 100,
walletBirthday: 1210000,
saplingActivation: network.constants.saplingActivationHeight,
network: network
)
var info = LightdInfo()
info.blockHeight = 130000
info.branch = "d34db33f"
@ -40,13 +58,15 @@ class BlockBatchValidationTests: XCTestCase {
let mockRust = MockRustBackend.self
mockRust.consensusBranchID = Int32(0xd34d)
let operation = FigureNextBatchOperation(downloader: downloader, service: service, config: config, rustBackend: mockRust)
let expectation = XCTestExpectation(description: "failure expectation")
let startedExpectation = XCTestExpectation(description: "start Expectation")
operation.startedHandler = {
startedExpectation.fulfill()
}
operation.errorHandler = { error in
expectation.fulfill()
switch error {
@ -58,17 +78,30 @@ class BlockBatchValidationTests: XCTestCase {
}
queue.addOperations([operation], waitUntilFinished: false)
wait(for: [startedExpectation,expectation], timeout: 1, enforceOrder: true)
wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true)
XCTAssertNotNil(operation.error)
XCTAssertTrue(operation.isCancelled)
}
func testBranchNetworkMismatchFailure() throws {
let network = ZcashNetworkBuilder.network(for: .mainnet)
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let service = MockLightWalletService(
latestBlockHeight: 1210000,
service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)
)
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.saplingActivationHeight, network: network)
let config = CompactBlockProcessor.Configuration(
cacheDb: try! __cacheDbURL(),
dataDb: try! __dataDbURL(),
downloadBatchSize: 100,
retries: 5,
maxBackoffInterval: 10,
rewindDistance: 100,
walletBirthday: 1210000,
saplingActivation: network.constants.saplingActivationHeight,
network: network
)
var info = LightdInfo()
info.blockHeight = 130000
info.branch = "d34db33f"
@ -76,17 +109,20 @@ class BlockBatchValidationTests: XCTestCase {
info.buildUser = "test user"
info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
service.mockLightDInfo = info
let mockRust = MockRustBackend.self
mockRust.consensusBranchID = 0xd34db4d
let operation = FigureNextBatchOperation(downloader: downloader, service: service, config: config, rustBackend: mockRust)
let expectation = XCTestExpectation(description: "failure expectation")
let startedExpectation = XCTestExpectation(description: "start Expectation")
operation.startedHandler = {
startedExpectation.fulfill()
}
operation.errorHandler = { error in
expectation.fulfill()
switch error {
@ -96,20 +132,33 @@ class BlockBatchValidationTests: XCTestCase {
XCTFail("Expected CompactBlockProcessorError.networkMismatch but found \(error)")
}
}
queue.addOperations([operation], waitUntilFinished: false)
wait(for: [startedExpectation,expectation], timeout: 1, enforceOrder: true)
wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true)
XCTAssertNotNil(operation.error)
XCTAssertTrue(operation.isCancelled)
}
func testBranchNetworkTypeWrongFailure() throws {
let network = ZcashNetworkBuilder.network(for: .testnet)
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let service = MockLightWalletService(
latestBlockHeight: 1210000,
service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)
)
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.saplingActivationHeight, network: network)
let config = CompactBlockProcessor.Configuration(
cacheDb: try! __cacheDbURL(),
dataDb: try! __dataDbURL(),
downloadBatchSize: 100,
retries: 5,
maxBackoffInterval: 10,
rewindDistance: 100,
walletBirthday: 1210000,
saplingActivation: network.constants.saplingActivationHeight,
network: network
)
var info = LightdInfo()
info.blockHeight = 130000
info.branch = "d34db33f"
@ -117,17 +166,20 @@ class BlockBatchValidationTests: XCTestCase {
info.buildUser = "test user"
info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
service.mockLightDInfo = info
let mockRust = MockRustBackend.self
mockRust.consensusBranchID = 0xd34db4d
let operation = FigureNextBatchOperation(downloader: downloader, service: service, config: config, rustBackend: mockRust)
let expectation = XCTestExpectation(description: "failure expectation")
let startedExpectation = XCTestExpectation(description: "start Expectation")
operation.startedHandler = {
startedExpectation.fulfill()
}
operation.errorHandler = { error in
expectation.fulfill()
switch error {
@ -137,19 +189,34 @@ class BlockBatchValidationTests: XCTestCase {
XCTFail("Expected CompactBlockProcessorError.generalError but found \(error)")
}
}
queue.addOperations([operation], waitUntilFinished: false)
wait(for: [startedExpectation,expectation], timeout: 1, enforceOrder: true)
wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true)
XCTAssertNotNil(operation.error)
XCTAssertTrue(operation.isCancelled)
}
func testSaplingActivationHeightMismatch() throws {
let network = ZcashNetworkBuilder.network(for: .mainnet)
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let service = MockLightWalletService(
latestBlockHeight: 1210000,
service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)
)
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.saplingActivationHeight, network: network)
let config = CompactBlockProcessor.Configuration(
cacheDb: try! __cacheDbURL(),
dataDb: try! __dataDbURL(),
downloadBatchSize: 100,
retries: 5,
maxBackoffInterval: 10,
rewindDistance: 100,
walletBirthday: 1210000,
saplingActivation: network.constants.saplingActivationHeight,
network: network
)
var info = LightdInfo()
info.blockHeight = 130000
info.branch = "d34db33f"
@ -157,29 +224,36 @@ class BlockBatchValidationTests: XCTestCase {
info.buildUser = "test user"
info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(3434343)
service.mockLightDInfo = info
let mockRust = MockRustBackend.self
mockRust.consensusBranchID = 0xd34db4d
let operation = FigureNextBatchOperation(downloader: downloader, service: service, config: config, rustBackend: mockRust)
let expectation = XCTestExpectation(description: "failure expectation")
let startedExpectation = XCTestExpectation(description: "start Expectation")
operation.startedHandler = {
startedExpectation.fulfill()
}
operation.errorHandler = { error in
expectation.fulfill()
switch error {
case CompactBlockProcessorError.saplingActivationMismatch(expected: network.constants.saplingActivationHeight, found: BlockHeight(info.saplingActivationHeight)):
case CompactBlockProcessorError.saplingActivationMismatch(
expected: network.constants.saplingActivationHeight,
found: BlockHeight(info.saplingActivationHeight)
):
break
default:
XCTFail("Expected CompactBlockProcessorError.saplingActivationMismatch but found \(error)")
}
}
queue.addOperations([operation], waitUntilFinished: false)
wait(for: [startedExpectation,expectation], timeout: 1, enforceOrder: true)
wait(for: [startedExpectation, expectation], timeout: 1, enforceOrder: true)
XCTAssertNotNil(operation.error)
XCTAssertTrue(operation.isCancelled)
}
@ -188,12 +262,29 @@ class BlockBatchValidationTests: XCTestCase {
let network = ZcashNetworkBuilder.network(for: .mainnet)
let expectedLatestHeight = BlockHeight(1210000)
let service = MockLightWalletService(latestBlockHeight: expectedLatestHeight, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let service = MockLightWalletService(
latestBlockHeight: expectedLatestHeight,
service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)
)
let expectedStoreLatestHeight = BlockHeight(1220000)
let expectedResult = FigureNextBatchOperation.NextState.wait(latestHeight: expectedLatestHeight, latestDownloadHeight: expectedLatestHeight)
let expectedResult = FigureNextBatchOperation.NextState.wait(
latestHeight: expectedLatestHeight,
latestDownloadHeight: expectedLatestHeight
)
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.saplingActivationHeight, network: network)
let config = CompactBlockProcessor.Configuration(
cacheDb: try! __cacheDbURL(),
dataDb: try! __dataDbURL(),
downloadBatchSize: 100,
retries: 5,
maxBackoffInterval: 10,
rewindDistance: 100,
walletBirthday: 1210000,
saplingActivation: network.constants.saplingActivationHeight,
network: network
)
var info = LightdInfo()
info.blockHeight = UInt64(expectedLatestHeight)
info.branch = "d34db33f"
@ -201,56 +292,84 @@ class BlockBatchValidationTests: XCTestCase {
info.buildUser = "test user"
info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
service.mockLightDInfo = info
let mockRust = MockRustBackend.self
mockRust.consensusBranchID = 0xd34db4d
let operation = FigureNextBatchOperation(downloader: downloader, service: service, config: config, rustBackend: mockRust)
let completedExpectation = XCTestExpectation(description: "completed expectation")
let startedExpectation = XCTestExpectation(description: "start Expectation")
operation.startedHandler = {
startedExpectation.fulfill()
}
operation.errorHandler = { error in
XCTFail("this shouldn't happen: \(error)")
}
operation.completionHandler = { (finished, cancelled) in
operation.completionHandler = { finished, cancelled in
completedExpectation.fulfill()
XCTAssertTrue(finished)
XCTAssertFalse(cancelled)
}
queue.addOperations([operation], waitUntilFinished: false)
wait(for: [startedExpectation,completedExpectation], timeout: 1, enforceOrder: true)
wait(for: [startedExpectation, completedExpectation], timeout: 1, enforceOrder: true)
XCTAssertNil(operation.error)
XCTAssertFalse(operation.isCancelled)
guard let result = operation.result else {
XCTFail("result should not be nil")
return
}
XCTAssertTrue({
switch result {
case .wait(latestHeight: expectedLatestHeight, latestDownloadHeight: expectedLatestHeight):
return true
default:
return false
}
}(), "Expected \(expectedResult) got: \(result)")
XCTAssertTrue(
{
switch result {
case .wait(latestHeight: expectedLatestHeight, latestDownloadHeight: expectedLatestHeight):
return true
default:
return false
}
}(),
"Expected \(expectedResult) got: \(result)"
)
}
func testResultProcessNew() throws {
let network = ZcashNetworkBuilder.network(for: .mainnet)
let expectedLatestHeight = BlockHeight(1230000)
let service = MockLightWalletService(latestBlockHeight: expectedLatestHeight, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let service = MockLightWalletService(
latestBlockHeight: expectedLatestHeight,
service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)
)
let expectedStoreLatestHeight = BlockHeight(1220000)
let walletBirthday = BlockHeight(1210000)
let expectedResult = FigureNextBatchOperation.NextState.processNewBlocks(range: CompactBlockProcessor.nextBatchBlockRange(latestHeight: expectedLatestHeight, latestDownloadedHeight: expectedStoreLatestHeight, walletBirthday: walletBirthday))
let expectedResult = FigureNextBatchOperation.NextState.processNewBlocks(
range: CompactBlockProcessor.nextBatchBlockRange(
latestHeight: expectedLatestHeight,
latestDownloadedHeight: expectedStoreLatestHeight,
walletBirthday: walletBirthday
)
)
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: walletBirthday, saplingActivation: network.constants.saplingActivationHeight, network: network)
let config = CompactBlockProcessor.Configuration(
cacheDb: try! __cacheDbURL(),
dataDb: try! __dataDbURL(),
downloadBatchSize: 100,
retries: 5,
maxBackoffInterval: 10,
rewindDistance: 100,
walletBirthday: walletBirthday,
saplingActivation: network.constants.saplingActivationHeight,
network: network
)
var info = LightdInfo()
info.blockHeight = UInt64(expectedLatestHeight)
info.branch = "d34db33f"
@ -258,56 +377,78 @@ class BlockBatchValidationTests: XCTestCase {
info.buildUser = "test user"
info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
service.mockLightDInfo = info
let mockRust = MockRustBackend.self
mockRust.consensusBranchID = 0xd34db4d
let operation = FigureNextBatchOperation(downloader: downloader, service: service, config: config, rustBackend: mockRust)
let completedExpectation = XCTestExpectation(description: "completed expectation")
let startedExpectation = XCTestExpectation(description: "start Expectation")
operation.startedHandler = {
startedExpectation.fulfill()
}
operation.errorHandler = { error in
operation.errorHandler = { _ in
XCTFail("this shouldn't happen")
}
operation.completionHandler = { (finished, cancelled) in
operation.completionHandler = { finished, cancelled in
completedExpectation.fulfill()
XCTAssertTrue(finished)
XCTAssertFalse(cancelled)
}
queue.addOperations([operation], waitUntilFinished: false)
wait(for: [startedExpectation,completedExpectation], timeout: 1, enforceOrder: true)
wait(for: [startedExpectation, completedExpectation], timeout: 1, enforceOrder: true)
XCTAssertNil(operation.error)
XCTAssertFalse(operation.isCancelled)
guard let result = operation.result else {
XCTFail("result should not be nil")
return
}
XCTAssertTrue({
switch result {
case .processNewBlocks(range: CompactBlockRange(uncheckedBounds: (expectedStoreLatestHeight + 1, expectedLatestHeight))):
return true
default:
return false
}
}(), "Expected \(expectedResult) got: \(result)")
XCTAssertTrue(
{
switch result {
case .processNewBlocks(range: CompactBlockRange(uncheckedBounds: (expectedStoreLatestHeight + 1, expectedLatestHeight))):
return true
default:
return false
}
}(),
"Expected \(expectedResult) got: \(result)"
)
}
func testResultProcessorFinished() throws {
let network = ZcashNetworkBuilder.network(for: .mainnet)
let expectedLatestHeight = BlockHeight(1230000)
let service = MockLightWalletService(latestBlockHeight: expectedLatestHeight, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let service = MockLightWalletService(
latestBlockHeight: expectedLatestHeight,
service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)
)
let expectedStoreLatestHeight = BlockHeight(1230000)
let walletBirthday = BlockHeight(1210000)
let expectedResult = FigureNextBatchOperation.NextState.finishProcessing(height: expectedStoreLatestHeight)
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: walletBirthday, saplingActivation: network.constants.saplingActivationHeight, network: network)
let config = CompactBlockProcessor.Configuration(
cacheDb: try! __cacheDbURL(),
dataDb: try! __dataDbURL(),
downloadBatchSize: 100,
retries: 5,
maxBackoffInterval: 10,
rewindDistance: 100,
walletBirthday: walletBirthday,
saplingActivation: network.constants.saplingActivationHeight,
network: network
)
var info = LightdInfo()
info.blockHeight = UInt64(expectedLatestHeight)
info.branch = "d34db33f"
@ -315,43 +456,51 @@ class BlockBatchValidationTests: XCTestCase {
info.buildUser = "test user"
info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
service.mockLightDInfo = info
let mockRust = MockRustBackend.self
mockRust.consensusBranchID = 0xd34db4d
let operation = FigureNextBatchOperation(downloader: downloader, service: service, config: config, rustBackend: mockRust)
let completedExpectation = XCTestExpectation(description: "completed expectation")
let startedExpectation = XCTestExpectation(description: "start Expectation")
operation.startedHandler = {
startedExpectation.fulfill()
}
operation.errorHandler = { error in
operation.errorHandler = { _ in
XCTFail("this shouldn't happen")
}
operation.completionHandler = { (finished, cancelled) in
operation.completionHandler = { finished, cancelled in
completedExpectation.fulfill()
XCTAssertTrue(finished)
XCTAssertFalse(cancelled)
}
queue.addOperations([operation], waitUntilFinished: false)
wait(for: [startedExpectation,completedExpectation], timeout: 1, enforceOrder: true)
wait(for: [startedExpectation, completedExpectation], timeout: 1, enforceOrder: true)
XCTAssertNil(operation.error)
XCTAssertFalse(operation.isCancelled)
guard let result = operation.result else {
XCTFail("result should not be nil")
return
}
XCTAssertTrue({
switch result {
case .finishProcessing(height: expectedLatestHeight):
return true
default:
return false
}
}(), "Expected \(expectedResult) got: \(result)")
XCTAssertTrue(
{
switch result {
case .finishProcessing(height: expectedLatestHeight):
return true
default:
return false
}
}(),
"Expected \(expectedResult) got: \(result)"
)
}
}

View File

@ -8,17 +8,21 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable implicitly_unwrapped_optional force_cast force_try
class BlockDownloaderTests: XCTestCase {
let branchID = "2bb40e60"
let chainName = "main"
var darksideWalletService: DarksideWalletService!
var downloader: CompactBlockDownloading!
var service: LightWalletService!
var storage: CompactBlockRepository!
var cacheDB = try! __cacheDbURL()
var network = DarksideWalletDNetwork()
var darksideWalletService: DarksideWalletService!
let branchID = "2bb40e60"
let chainName = "main"
override func setUpWithError() throws {
try super.setUpWithError()
service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)
storage = try! TestDbBuilder.diskCompactBlockStorage(at: cacheDB)
downloader = CompactBlockDownloader(service: service, storage: storage)
@ -29,7 +33,7 @@ class BlockDownloaderTests: XCTestCase {
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
try super.tearDown()
service = nil
storage = nil
downloader = nil
@ -37,24 +41,23 @@ class BlockDownloaderTests: XCTestCase {
}
func testSmallDownloadAsync() {
let expect = XCTestExpectation(description: self.description)
expect.expectedFulfillmentCount = 3
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange))
downloader.downloadBlockRange(range) { (error) in
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
downloader.downloadBlockRange(range) { error in
expect.fulfill()
XCTAssertNil(error)
// check what was 'stored'
self.storage.latestHeight { (result) in
self.storage.latestHeight { result in
expect.fulfill()
XCTAssertTrue(self.validate(result: result, against: upperRange))
self.downloader.lastDownloadedBlockHeight { (resultHeight) in
self.downloader.lastDownloadedBlockHeight { resultHeight in
expect.fulfill()
XCTAssertTrue(self.validate(result: resultHeight, against: upperRange))
}
@ -65,11 +68,10 @@ 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))
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
var latest: BlockHeight = 0
do {
@ -84,26 +86,31 @@ class BlockDownloaderTests: XCTestCase {
var currentLatest: BlockHeight = 0
do {
currentLatest = try downloader.lastDownloadedBlockHeight()
} catch {
XCTFail("latest block failed")
return
}
XCTAssertEqual(currentLatest,upperRange )
XCTAssertEqual(currentLatest, upperRange )
}
func testFailure() {
let awfulDownloader = CompactBlockDownloader(service: AwfulLightWalletService(latestBlockHeight: self.network.constants.saplingActivationHeight + 1000, service: darksideWalletService), storage: ZcashConsoleFakeStorage())
let awfulDownloader = CompactBlockDownloader(
service: AwfulLightWalletService(
latestBlockHeight: self.network.constants.saplingActivationHeight + 1000,
service: darksideWalletService
),
storage: ZcashConsoleFakeStorage()
)
let expect = XCTestExpectation(description: self.description)
expect.expectedFulfillmentCount = 1
let lowerRange: BlockHeight = self.network.constants.saplingActivationHeight
let upperRange: BlockHeight = self.network.constants.saplingActivationHeight + 99
let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange))
let range = CompactBlockRange(uncheckedBounds: (lowerRange, upperRange))
awfulDownloader.downloadBlockRange(range) { (error) in
awfulDownloader.downloadBlockRange(range) { error in
expect.fulfill()
XCTAssertNotNil(error)
}
@ -114,14 +121,12 @@ class BlockDownloaderTests: XCTestCase {
/// Helper functions
extension BlockDownloaderTests {
func validate(result: Result<BlockHeight,Error> ,against height: BlockHeight) -> Bool {
func validate(result: Result<BlockHeight, Error>, against height: BlockHeight) -> Bool {
switch result {
case .success(let resultHeight):
return resultHeight == height
default:
return false
}
}
}

View File

@ -9,23 +9,31 @@
import XCTest
import SQLite
@testable import ZcashLightClientKit
// swiftlint:disable implicitly_unwrapped_optional force_try force_unwrapping print_function_usage
class BlockScanOperationTests: XCTestCase {
let rustWelding = ZcashRustBackend.self
var operationQueue = OperationQueue()
var cacheDbURL: URL!
var dataDbURL: URL!
let rustWelding = ZcashRustBackend.self
var uvk = UVFakeKey(extfvk: "zxviewtestsapling1qw88ayg8qqqqpqyhg7jnh9mlldejfqwu46pm40ruwstd8znq3v3l4hjf33qcu2a5e36katshcfhcxhzgyfugj2lkhmt40j45cv38rv3frnghzkxcx73k7m7afw9j7ujk7nm4dx5mv02r26umxqgar7v3x390w2h3crqqgjsjly7jy4vtwzrmustm5yudpgcydw7x78awca8wqjvkqj8p8e3ykt7lrgd7xf92fsfqjs5vegfsja4ekzpfh5vtccgvs5747xqm6qflmtqpr8s9u",
extpub: "02075a7f5f7507d64022dad5954849f216b0f1b09b2d588be663d8e7faeb5aaf61")
var walletBirthDay = WalletBirthday.birthday(with: 1386000, network: ZcashNetworkBuilder.network(for: .testnet))
var uvk = UVFakeKey(
extfvk: "zxviewtestsapling1qw88ayg8qqqqpqyhg7jnh9mlldejfqwu46pm40ruwstd8znq3v3l4hjf33qcu2a5e36katshcfhcxhzgyfugj2lkhmt40j45cv38rv3frnghzkxcx73k7m7afw9j7ujk7nm4dx5mv02r26umxqgar7v3x390w2h3crqqgjsjly7jy4vtwzrmustm5yudpgcydw7x78awca8wqjvkqj8p8e3ykt7lrgd7xf92fsfqjs5vegfsja4ekzpfh5vtccgvs5747xqm6qflmtqpr8s9u", // swiftlint:disable:this line_length
extpub: "02075a7f5f7507d64022dad5954849f216b0f1b09b2d588be663d8e7faeb5aaf61"
)
var walletBirthDay = WalletBirthday.birthday(
with: 1386000,
network: ZcashNetworkBuilder.network(for: .testnet)
)
var network = ZcashNetworkBuilder.network(for: .testnet)
var blockRepository: BlockRepository!
override func setUp() {
// Put setup code here. This method is called before the invocation of each test method in the class.
super.setUp()
self.cacheDbURL = try! __cacheDbURL()
self.dataDbURL = try! __dataDbURL()
@ -37,8 +45,10 @@ class BlockScanOperationTests: XCTestCase {
try? FileManager.default.removeItem(at: cacheDbURL)
try? FileManager.default.removeItem(at: dataDbURL)
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
operationQueue.cancelAllOperations()
try? FileManager.default.removeItem(at: cacheDbURL)
@ -47,29 +57,47 @@ class BlockScanOperationTests: XCTestCase {
func testSingleDownloadAndScanOperation() {
logger = SampleLogger(logLevel: .debug)
XCTAssertNoThrow(try rustWelding.initDataDb(dbData: dataDbURL, networkType: network.networkType))
let downloadStartedExpect = XCTestExpectation(description: self.description + "download started")
let downloadExpect = XCTestExpectation(description: self.description + "download")
let scanStartedExpect = XCTestExpectation(description: self.description + "scan started")
let scanExpect = XCTestExpectation(description: self.description + "scan")
let latestScannedBlockExpect = XCTestExpectation(description: self.description + "latestScannedHeight")
let service = LightWalletGRPCService(endpoint: LightWalletEndpoint(address: "lightwalletd.testnet.electriccoin.co", port: 9067))
let downloadStartedExpect = XCTestExpectation(description: "\(self.description) download started")
let downloadExpect = XCTestExpectation(description: "\(self.description) download")
let scanStartedExpect = XCTestExpectation(description: "\(self.description) scan started")
let scanExpect = XCTestExpectation(description: "\(self.description) scan")
let latestScannedBlockExpect = XCTestExpectation(description: "\(self.description) latestScannedHeight")
let service = LightWalletGRPCService(
endpoint: LightWalletEndpoint(
address: "lightwalletd.testnet.electriccoin.co",
port: 9067
)
)
let blockCount = 100
let range = network.constants.saplingActivationHeight ... network.constants.saplingActivationHeight + blockCount
let downloadOperation = CompactBlockDownloadOperation(downloader: CompactBlockDownloader.sqlDownloader(service: service, at: cacheDbURL)!, range: range)
let scanOperation = CompactBlockScanningOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL, networkType: network.networkType)
let range = network.constants.saplingActivationHeight ... network.constants.saplingActivationHeight + blockCount
let downloadOperation = CompactBlockDownloadOperation(
downloader: CompactBlockDownloader.sqlDownloader(
service: service,
at: cacheDbURL
)!,
range: range
)
let scanOperation = CompactBlockScanningOperation(
rustWelding: rustWelding,
cacheDb: cacheDbURL,
dataDb: dataDbURL,
networkType: network.networkType
)
downloadOperation.startedHandler = {
downloadStartedExpect.fulfill()
}
downloadOperation.completionHandler = { (finished, cancelled) in
downloadOperation.completionHandler = { finished, cancelled in
downloadExpect.fulfill()
XCTAssertTrue(finished)
XCTAssertFalse(cancelled)
}
downloadOperation.errorHandler = { (error) in
downloadOperation.errorHandler = { error in
XCTFail("Download Operation failed with Error: \(error)")
}
@ -77,13 +105,13 @@ class BlockScanOperationTests: XCTestCase {
scanStartedExpect.fulfill()
}
scanOperation.completionHandler = { (finished, cancelled) in
scanOperation.completionHandler = { finished, cancelled in
scanExpect.fulfill()
XCTAssertFalse(cancelled)
XCTAssertTrue(finished)
}
scanOperation.errorHandler = { (error) in
scanOperation.errorHandler = { error in
XCTFail("Scan Operation failed with Error: \(error)")
}
@ -101,10 +129,16 @@ class BlockScanOperationTests: XCTestCase {
latestScannedBlockOperation.addDependency(scanOperation)
operationQueue.addOperations([downloadOperation,scanOperation,latestScannedBlockOperation], waitUntilFinished: false)
wait(for: [downloadStartedExpect, downloadExpect, scanStartedExpect, scanExpect,latestScannedBlockExpect], timeout: 10, enforceOrder: true)
operationQueue.addOperations(
[downloadOperation, scanOperation, latestScannedBlockOperation],
waitUntilFinished: false
)
wait(
for: [downloadStartedExpect, downloadExpect, scanStartedExpect, scanExpect, latestScannedBlockExpect],
timeout: 10,
enforceOrder: true
)
}
@objc func observeBenchmark(_ notification: Notification) {
guard let report = SDKMetrics.blockReportFromNotification(notification) else {
@ -112,20 +146,32 @@ class BlockScanOperationTests: XCTestCase {
}
print("observed benchmark: \(report)")
}
func testScanValidateDownload() throws {
logger = SampleLogger(logLevel: .debug)
NotificationCenter.default.addObserver(self, selector: #selector(observeBenchmark(_:)), name: SDKMetrics.notificationName, object: nil)
NotificationCenter.default.addObserver(
self,
selector: #selector(observeBenchmark(_:)),
name: SDKMetrics.notificationName,
object: nil
)
try self.rustWelding.initDataDb(dbData: dataDbURL, networkType: network.networkType)
guard try self.rustWelding.initAccountsTable(dbData: self.dataDbURL, uvks: [uvk], networkType: network.networkType) else {
XCTFail("failed to init account table")
return
}
try self.rustWelding.initBlocksTable(dbData: dataDbURL, height: Int32(walletBirthDay.height), hash: walletBirthDay.hash, time: walletBirthDay.time, saplingTree: walletBirthDay.tree, networkType: network.networkType)
try self.rustWelding.initBlocksTable(
dbData: dataDbURL,
height: Int32(walletBirthDay.height),
hash: walletBirthDay.hash,
time: walletBirthDay.time,
saplingTree: walletBirthDay.tree,
networkType: network.networkType
)
let service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet)
let storage = CompactBlockStorage(url: cacheDbURL, readonly: false)
@ -135,13 +181,15 @@ class BlockScanOperationTests: XCTestCase {
let validateExpectation = XCTestExpectation(description: "validate expectation")
let scanExpectation = XCTestExpectation(description: "scan expectation")
let downloadOperation = CompactBlockStreamDownloadOperation(service: service,
storage: storage,
startHeight: walletBirthDay.height,
targetHeight: walletBirthDay.height + 10000,
progressDelegate: self)
let downloadOperation = CompactBlockStreamDownloadOperation(
service: service,
storage: storage,
startHeight: walletBirthDay.height,
targetHeight: walletBirthDay.height + 10000,
progressDelegate: self
)
downloadOperation.completionHandler = { (finished, cancelled) in
downloadOperation.completionHandler = { finished, cancelled in
XCTAssert(finished)
XCTAssertFalse(cancelled)
downloadExpectation.fulfill()
@ -160,40 +208,55 @@ class BlockScanOperationTests: XCTestCase {
}
}
let validationOperation = CompactBlockValidationOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL, networkType: network.networkType)
let validationOperation = CompactBlockValidationOperation(
rustWelding: rustWelding,
cacheDb: cacheDbURL,
dataDb: dataDbURL,
networkType: network.networkType
)
validationOperation.errorHandler = { error in
self.operationQueue.cancelAllOperations()
XCTFail("failed with error \(error)")
}
validationOperation.completionHandler = { (finished,cancelled) in
validationOperation.completionHandler = { finished, cancelled in
XCTAssert(finished)
XCTAssertFalse(cancelled)
validateExpectation.fulfill()
}
let transactionRepository = TransactionRepositoryBuilder.build(dataDbURL: dataDbURL)
let scanningOperation = CompactBlockBatchScanningOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL, transactionRepository: transactionRepository, range: CompactBlockRange(uncheckedBounds: (walletBirthDay.height, walletBirthDay.height + 10000)), batchSize: 1000, networkType: network.networkType, progressDelegate: self)
let scanningOperation = CompactBlockBatchScanningOperation(
rustWelding: rustWelding,
cacheDb: cacheDbURL,
dataDb: dataDbURL,
transactionRepository: transactionRepository,
range: CompactBlockRange(
uncheckedBounds: (walletBirthDay.height, walletBirthDay.height + 10000)
),
batchSize: 1000,
networkType: network.networkType,
progressDelegate: self
)
scanningOperation.completionHandler = { (finished,cancelled) in
scanningOperation.completionHandler = { finished, cancelled in
XCTAssert(finished)
XCTAssertFalse(cancelled)
scanExpectation.fulfill()
}
operationQueue.addOperations([downloadOperation, validationOperation, scanningOperation], waitUntilFinished: false)
wait(for: [downloadExpectation,validateExpectation,scanExpectation], timeout: 300, enforceOrder: true)
wait(for: [downloadExpectation, validateExpectation, scanExpectation], timeout: 300, enforceOrder: true)
}
}
extension BlockScanOperationTests: CompactBlockProgressDelegate {
func progressUpdated(_ progress: CompactBlockProgress) {
// print("progressHeight: \(progress.progressHeight) startHeight: \(progress.startHeight), targetHeight: \(progress.targetHeight)")
}
}
struct UVFakeKey: UnifiedViewingKey {
var extfvk: ExtendedFullViewingKey
var extpub: ExtendedPublicKey

View File

@ -7,36 +7,40 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable print_function_usage
class BlockStreamingTest: XCTestCase {
var queue: OperationQueue = {
let q = OperationQueue()
q.maxConcurrentOperationCount = 1
return q
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
return queue
}()
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
try super.setUpWithError()
logger = SampleLogger(logLevel: .debug)
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
try super.tearDownWithError()
try? FileManager.default.removeItem(at: __dataDbURL())
}
func testStreamOperation() throws {
let expectation = XCTestExpectation(description: "blockstream expectation")
let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067,
secure: true,
singleCallTimeout: 1000,
streamingCallTimeout: 100000)
let service = LightWalletGRPCService(
host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067,
secure: true,
singleCallTimeout: 1000,
streamingCallTimeout: 100000
)
let latestHeight = try service.latestBlockHeight()
let startHeight = latestHeight - 100_000
var blocks = [ZcashCompactBlock]()
var blocks: [ZcashCompactBlock] = []
service.blockStream(startHeight: startHeight, endHeight: latestHeight) { result in
expectation.fulfill()
switch result {
@ -49,29 +53,34 @@ class BlockStreamingTest: XCTestCase {
print("received block \(compactBlock.height)")
blocks.append(compactBlock)
} progress: { progressReport in
print("progressHeight: \(progressReport.progressHeight) startHeight: \(progressReport.startHeight), targetHeight: \(progressReport.targetHeight)")
print("progressHeight: \(progressReport.progressHeight)")
print("startHeight: \(progressReport.startHeight)")
print("targetHeight: \(progressReport.targetHeight)")
}
wait(for: [expectation], timeout: 1000)
}
func testStreamOperationCancellation() throws {
let expectation = XCTestExpectation(description: "blockstream expectation")
let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067,
secure: true,
singleCallTimeout: 10000,
streamingCallTimeout: 10000)
let service = LightWalletGRPCService(
host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067,
secure: true,
singleCallTimeout: 10000,
streamingCallTimeout: 10000
)
let storage = try TestDbBuilder.inMemoryCompactBlockStorage()
let startHeight = try service.latestBlockHeight() - 100_000
let operation = CompactBlockStreamDownloadOperation(service: service,
storage: storage,
startHeight: startHeight,
progressDelegate: self)
let operation = CompactBlockStreamDownloadOperation(
service: service,
storage: storage,
startHeight: startHeight,
progressDelegate: self
)
operation.completionHandler = { (finished, cancelled) in
operation.completionHandler = { _, cancelled in
XCTAssert(cancelled)
expectation.fulfill()
}
@ -91,20 +100,24 @@ class BlockStreamingTest: XCTestCase {
func testStreamOperationTimeout() throws {
let expectation = XCTestExpectation(description: "blockstream expectation")
let errorExpectation = XCTestExpectation(description: "blockstream error expectation")
let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067,
secure: true,
singleCallTimeout: 1000,
streamingCallTimeout: 3000)
let service = LightWalletGRPCService(
host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067,
secure: true,
singleCallTimeout: 1000,
streamingCallTimeout: 3000
)
let storage = try TestDbBuilder.inMemoryCompactBlockStorage()
let startHeight = try service.latestBlockHeight() - 100_000
let operation = CompactBlockStreamDownloadOperation(service: service,
storage: storage,
startHeight: startHeight,
progressDelegate: self)
let operation = CompactBlockStreamDownloadOperation(
service: service,
storage: storage,
startHeight: startHeight,
progressDelegate: self
)
operation.completionHandler = { (finished, cancelled) in
operation.completionHandler = { finished, _ in
XCTAssert(finished)
expectation.fulfill()
@ -136,20 +149,25 @@ class BlockStreamingTest: XCTestCase {
func testBatchOperation() throws {
let expectation = XCTestExpectation(description: "blockbatch expectation")
let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067,
secure: true,
singleCallTimeout: 300000,
streamingCallTimeout: 10000)
let service = LightWalletGRPCService(
host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067,
secure: true,
singleCallTimeout: 300000,
streamingCallTimeout: 10000
)
let storage = try TestDbBuilder.diskCompactBlockStorage(at: __dataDbURL() )
let targetHeight = try service.latestBlockHeight()
let startHeight = targetHeight - 10_000
let operation = CompactBlockBatchDownloadOperation(service: service,
storage: storage,
startHeight: startHeight, targetHeight: targetHeight,
progressDelegate: self)
let startHeight = targetHeight - 10_000
let operation = CompactBlockBatchDownloadOperation(
service: service,
storage: storage,
startHeight: startHeight,
targetHeight: targetHeight,
progressDelegate: self
)
operation.completionHandler = { (finished, cancelled) in
operation.completionHandler = { _, cancelled in
if cancelled {
XCTFail("operation cancelled")
}
@ -169,20 +187,25 @@ class BlockStreamingTest: XCTestCase {
func testBatchOperationCancellation() throws {
let expectation = XCTestExpectation(description: "blockbatch expectation")
let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067,
secure: true,
singleCallTimeout: 300000,
streamingCallTimeout: 10000)
let service = LightWalletGRPCService(
host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067,
secure: true,
singleCallTimeout: 300000,
streamingCallTimeout: 10000
)
let storage = try TestDbBuilder.diskCompactBlockStorage(at: __dataDbURL() )
let targetHeight = try service.latestBlockHeight()
let startHeight = targetHeight - 100_000
let operation = CompactBlockBatchDownloadOperation(service: service,
storage: storage,
startHeight: startHeight, targetHeight: targetHeight,
progressDelegate: self)
let startHeight = targetHeight - 100_000
let operation = CompactBlockBatchDownloadOperation(
service: service,
storage: storage,
startHeight: startHeight,
targetHeight: targetHeight,
progressDelegate: self
)
operation.completionHandler = { (finished, cancelled) in
operation.completionHandler = { _, cancelled in
XCTAssert(cancelled)
expectation.fulfill()
}
@ -201,8 +224,9 @@ class BlockStreamingTest: XCTestCase {
}
extension BlockStreamingTest: CompactBlockProgressDelegate {
func progressUpdated(_ progress: CompactBlockProgress) {
print("progressHeight: \(String(describing: progress.progressHeight)) startHeight: \(progress.progress), targetHeight: \(String(describing: progress.targetHeight))")
print("progressHeight: \(String(describing: progress.progressHeight))")
print("startHeight: \(progress.progress)")
print("targetHeight: \(String(describing: progress.targetHeight))")
}
}

View File

@ -8,9 +8,13 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable force_try implicitly_unwrapped_optional
class CompactBlockProcessorTests: XCTestCase {
let processorConfig = CompactBlockProcessor.Configuration.standard(for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight)
let processorConfig = CompactBlockProcessor.Configuration.standard(
for: ZcashNetworkBuilder.network(for: .testnet),
walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight
)
var processor: CompactBlockProcessor!
var downloadStartedExpect: XCTestExpectation!
var updatedNotificationExpectation: XCTestExpectation!
@ -22,10 +26,13 @@ class CompactBlockProcessorTests: XCTestCase {
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
try super.setUpWithError()
logger = SampleLogger(logLevel: .debug)
let service = MockLightWalletService(latestBlockHeight: mockLatestHeight, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet))
let service = MockLightWalletService(
latestBlockHeight: mockLatestHeight,
service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet)
)
let branchID = try ZcashRustBackend.consensusBranchIdFor(height: Int32(mockLatestHeight), networkType: network.networkType)
service.mockLightDInfo = LightdInfo.with({ info in
info.blockHeight = UInt64(mockLatestHeight)
@ -41,23 +48,33 @@ class CompactBlockProcessorTests: XCTestCase {
let storage = CompactBlockStorage.init(connectionProvider: SimpleConnectionProvider(path: processorConfig.cacheDb.absoluteString))
try! storage.createTable()
processor = CompactBlockProcessor(service: service,
storage: storage,
backend: ZcashRustBackend.self,
config: processorConfig)
processor = CompactBlockProcessor(
service: service,
storage: storage,
backend: ZcashRustBackend.self,
config: processorConfig
)
try ZcashRustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: .testnet)
downloadStartedExpect = XCTestExpectation(description: self.description + " downloadStartedExpect")
stopNotificationExpectation = XCTestExpectation(description: self.description + " stopNotificationExpectation")
updatedNotificationExpectation = XCTestExpectation(description: self.description + " updatedNotificationExpectation")
startedValidatingNotificationExpectation = XCTestExpectation(description: self.description + " startedValidatingNotificationExpectation")
startedScanningNotificationExpectation = XCTestExpectation(description: self.description + " startedScanningNotificationExpectation")
idleNotificationExpectation = XCTestExpectation(description: self.description + " idleNotificationExpectation")
NotificationCenter.default.addObserver(self, selector: #selector(processorFailed(_:)), name: Notification.Name.blockProcessorFailed, object: processor)
downloadStartedExpect = XCTestExpectation(description: "\(self.description) downloadStartedExpect")
stopNotificationExpectation = XCTestExpectation(description: "\(self.description) stopNotificationExpectation")
updatedNotificationExpectation = XCTestExpectation(description: "\(self.description) updatedNotificationExpectation")
startedValidatingNotificationExpectation = XCTestExpectation(
description: "\(self.description) startedValidatingNotificationExpectation"
)
startedScanningNotificationExpectation = XCTestExpectation(
description: "\(self.description) startedScanningNotificationExpectation"
)
idleNotificationExpectation = XCTestExpectation(description: "\(self.description) idleNotificationExpectation")
NotificationCenter.default.addObserver(
self,
selector: #selector(processorFailed(_:)),
name: Notification.Name.blockProcessorFailed,
object: processor
)
}
override func tearDown() {
super.tearDown()
try! FileManager.default.removeItem(at: processorConfig.cacheDb)
try? FileManager.default.removeItem(at: processorConfig.dataDb)
downloadStartedExpect.unsubscribeFromNotifications()
@ -78,7 +95,7 @@ class CompactBlockProcessorTests: XCTestCase {
}
}
fileprivate func startProcessing() {
private func startProcessing() {
XCTAssertNotNil(processor)
// Subscribe to notifications
@ -93,41 +110,51 @@ class CompactBlockProcessorTests: XCTestCase {
}
func testStartNotifiesSuscriptors() {
startProcessing()
wait(for: [
downloadStartedExpect,
startedValidatingNotificationExpectation,
startedScanningNotificationExpectation,
idleNotificationExpectation,
], timeout: 30,enforceOrder: true)
wait(
for: [
downloadStartedExpect,
startedValidatingNotificationExpectation,
startedScanningNotificationExpectation,
idleNotificationExpectation
],
timeout: 30,
enforceOrder: true
)
}
func testProgressNotifications() {
let expectedUpdates = expectedBatches(currentHeight: processorConfig.walletBirthday, targetHeight: mockLatestHeight, batchSize: processorConfig.downloadBatchSize)
let expectedUpdates = expectedBatches(
currentHeight: processorConfig.walletBirthday,
targetHeight: mockLatestHeight,
batchSize: processorConfig.downloadBatchSize
)
updatedNotificationExpectation.expectedFulfillmentCount = expectedUpdates
startProcessing()
wait(for: [updatedNotificationExpectation], timeout: 300)
}
private func expectedBatches(currentHeight: BlockHeight, targetHeight: BlockHeight, batchSize: Int) -> Int {
(abs(currentHeight-targetHeight)/batchSize)
(abs(currentHeight - targetHeight) / batchSize)
}
func testNextBatchBlockRange() {
// test first range
var latestDownloadedHeight = processorConfig.walletBirthday // this can be either this or Wallet Birthday.
var latestBlockchainHeight = BlockHeight(network.constants.saplingActivationHeight + 1000)
var expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight, upper:latestBlockchainHeight))
XCTAssertEqual(expectedBatchRange, CompactBlockProcessor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight, walletBirthday: processorConfig.walletBirthday))
XCTAssertEqual(
expectedBatchRange,
CompactBlockProcessor.nextBatchBlockRange(
latestHeight: latestBlockchainHeight,
latestDownloadedHeight: latestDownloadedHeight,
walletBirthday: processorConfig.walletBirthday
)
)
// Test mid-range
latestDownloadedHeight = BlockHeight(network.constants.saplingActivationHeight + ZcashSDK.DefaultBatchSize)
@ -135,7 +162,14 @@ class CompactBlockProcessorTests: XCTestCase {
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))
XCTAssertEqual(expectedBatchRange, CompactBlockProcessor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight, walletBirthday: processorConfig.walletBirthday))
XCTAssertEqual(
expectedBatchRange,
CompactBlockProcessor.nextBatchBlockRange(
latestHeight: latestBlockchainHeight,
latestDownloadedHeight: latestDownloadedHeight,
walletBirthday: processorConfig.walletBirthday
)
)
// Test last batch range
@ -144,7 +178,14 @@ class CompactBlockProcessorTests: XCTestCase {
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))
XCTAssertEqual(expectedBatchRange, CompactBlockProcessor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight, walletBirthday: processorConfig.walletBirthday))
XCTAssertEqual(
expectedBatchRange,
CompactBlockProcessor.nextBatchBlockRange(
latestHeight: latestBlockchainHeight,
latestDownloadedHeight: latestDownloadedHeight,
walletBirthday: processorConfig.walletBirthday
)
)
}
func testDetermineLowerBoundPastBirthday() {
@ -156,7 +197,6 @@ class CompactBlockProcessorTests: XCTestCase {
let expected = 781_886
XCTAssertEqual(result, expected)
}
func testDetermineLowerBound() {
@ -168,6 +208,5 @@ class CompactBlockProcessorTests: XCTestCase {
let expected = 781_896
XCTAssertEqual(result, expected)
}
}

View File

@ -6,12 +6,15 @@
//
// Copyright © 2019 Electric Coin Company. All rights reserved.
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable implicitly_unwrapped_optional force_try
class CompactBlockReorgTests: XCTestCase {
let processorConfig = CompactBlockProcessor.Configuration.standard(for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight)
let processorConfig = CompactBlockProcessor.Configuration.standard(
for: ZcashNetworkBuilder.network(for: .testnet),
walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight
)
var processor: CompactBlockProcessor!
var downloadStartedExpect: XCTestExpectation!
var updatedNotificationExpectation: XCTestExpectation!
@ -24,13 +27,15 @@ class CompactBlockReorgTests: XCTestCase {
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight + 2000
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
try super.setUpWithError()
logger = SampleLogger(logLevel: .debug)
let service = MockLightWalletService(latestBlockHeight: mockLatestHeight, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet))
let service = MockLightWalletService(
latestBlockHeight: mockLatestHeight,
service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet)
)
let branchID = try ZcashRustBackend.consensusBranchIdFor(height: Int32(mockLatestHeight), networkType: network.networkType)
service.mockLightDInfo = LightdInfo.with({ info in
service.mockLightDInfo = LightdInfo.with { info in
info.blockHeight = UInt64(mockLatestHeight)
info.branch = "asdf"
info.buildDate = "today"
@ -39,7 +44,7 @@ class CompactBlockReorgTests: XCTestCase {
info.consensusBranchID = branchID.toString()
info.estimatedHeight = UInt64(mockLatestHeight)
info.saplingActivationHeight = UInt64(network.constants.saplingActivationHeight)
})
}
try ZcashRustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: .testnet)
@ -51,24 +56,42 @@ class CompactBlockReorgTests: XCTestCase {
mockBackend.mockValidateCombinedChainKeepFailing = false
mockBackend.mockValidateCombinedChainFailureHeight = self.network.constants.saplingActivationHeight + 320
processor = CompactBlockProcessor(service: service,
storage: storage,
backend: mockBackend,
config: processorConfig)
processor = CompactBlockProcessor(
service: service,
storage: storage,
backend: mockBackend,
config: processorConfig
)
downloadStartedExpect = XCTestExpectation(description: self.description + " downloadStartedExpect")
stopNotificationExpectation = XCTestExpectation(description: self.description + " stopNotificationExpectation")
updatedNotificationExpectation = XCTestExpectation(description: self.description + " updatedNotificationExpectation")
startedValidatingNotificationExpectation = XCTestExpectation(description: self.description + " startedValidatingNotificationExpectation")
startedScanningNotificationExpectation = XCTestExpectation(description: self.description + " startedScanningNotificationExpectation")
idleNotificationExpectation = XCTestExpectation(description: self.description + " idleNotificationExpectation")
reorgNotificationExpectation = XCTestExpectation(description: self.description + " reorgNotificationExpectation")
downloadStartedExpect = XCTestExpectation(description: "\(self.description) downloadStartedExpect")
stopNotificationExpectation = XCTestExpectation(description: "\(self.description) stopNotificationExpectation")
updatedNotificationExpectation = XCTestExpectation(description: "\(self.description) updatedNotificationExpectation")
startedValidatingNotificationExpectation = XCTestExpectation(
description: "\(self.description) startedValidatingNotificationExpectation"
)
startedScanningNotificationExpectation = XCTestExpectation(
description: "\(self.description) startedScanningNotificationExpectation"
)
idleNotificationExpectation = XCTestExpectation(description: "\(self.description) idleNotificationExpectation")
reorgNotificationExpectation = XCTestExpectation(description: "\(self.description) reorgNotificationExpectation")
NotificationCenter.default.addObserver(self, selector: #selector(processorHandledReorg(_:)), name: Notification.Name.blockProcessorHandledReOrg, object: processor)
NotificationCenter.default.addObserver(self, selector: #selector(processorFailed(_:)), name: Notification.Name.blockProcessorFailed, object: processor)
NotificationCenter.default.addObserver(
self,
selector: #selector(processorHandledReorg(_:)),
name: Notification.Name.blockProcessorHandledReOrg,
object: processor
)
NotificationCenter.default.addObserver(
self,
selector: #selector(processorFailed(_:)),
name: Notification.Name.blockProcessorFailed,
object: processor
)
}
override func tearDown() {
super.tearDown()
try! FileManager.default.removeItem(at: processorConfig.cacheDb)
try? FileManager.default.removeItem(at: processorConfig.dataDb)
downloadStartedExpect.unsubscribeFromNotifications()
@ -82,31 +105,28 @@ class CompactBlockReorgTests: XCTestCase {
}
@objc func processorHandledReorg(_ notification: Notification) {
XCTAssertNotNil(notification.userInfo)
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
XCTAssertTrue( reorg == 0 || reorg > self.network.constants.saplingActivationHeight)
XCTAssertTrue( rewind == 0 || rewind > self.network.constants.saplingActivationHeight)
XCTAssertTrue( rewind <= reorg )
reorgNotificationExpectation.fulfill()
} else {
XCTFail("CompactBlockProcessor reorg notification is malformed")
}
XCTAssertNotNil(notification.userInfo)
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
XCTAssertTrue( reorg == 0 || reorg > self.network.constants.saplingActivationHeight)
XCTAssertTrue( rewind == 0 || rewind > self.network.constants.saplingActivationHeight)
XCTAssertTrue( rewind <= reorg )
reorgNotificationExpectation.fulfill()
} else {
XCTFail("CompactBlockProcessor reorg notification is malformed")
}
}
@objc func processorFailed(_ notification: Notification) {
XCTAssertNotNil(notification.userInfo)
if let error = notification.userInfo?["error"] {
XCTFail("CompactBlockProcessor failed with Error: \(error)")
} else {
XCTFail("CompactBlockProcessor failed")
}
XCTAssertNotNil(notification.userInfo)
if let error = notification.userInfo?["error"] {
XCTFail("CompactBlockProcessor failed with Error: \(error)")
} else {
XCTFail("CompactBlockProcessor failed")
}
}
fileprivate func startProcessing() {
private func startProcessing() {
XCTAssertNotNil(processor)
// Subscribe to notifications
@ -122,20 +142,22 @@ class CompactBlockReorgTests: XCTestCase {
}
func testNotifiesReorg() {
startProcessing()
wait(for: [
downloadStartedExpect,
startedValidatingNotificationExpectation,
startedScanningNotificationExpectation,
reorgNotificationExpectation,
idleNotificationExpectation,
], timeout: 300,enforceOrder: true)
wait(
for: [
downloadStartedExpect,
startedValidatingNotificationExpectation,
startedScanningNotificationExpectation,
reorgNotificationExpectation,
idleNotificationExpectation
],
timeout: 300,
enforceOrder: true
)
}
private func expectedBatches(currentHeight: BlockHeight, targetHeight: BlockHeight, batchSize: Int) -> Int {
(abs(currentHeight-targetHeight)/batchSize)
(abs(currentHeight - targetHeight) / batchSize)
}
}

View File

@ -8,12 +8,13 @@
import Foundation
import XCTest
// swiftlint:disable force_try
@testable import ZcashLightClientKit
class CompactBlockStorageTests: XCTestCase {
var compactBlockDao: CompactBlockRepository = try! TestDbBuilder.inMemoryCompactBlockStorage()
let network = ZcashNetworkBuilder.network(for: .testnet)
var compactBlockDao: CompactBlockRepository = try! TestDbBuilder.inMemoryCompactBlockStorage()
func testEmptyStorage() {
XCTAssertEqual(try! compactBlockDao.latestHeight(), BlockHeight.empty())
}
@ -34,11 +35,9 @@ class CompactBlockStorageTests: XCTestCase {
let latestHeight = try! compactBlockDao.latestHeight()
XCTAssertNotEqual(initialHeight, latestHeight)
XCTAssertEqual(latestHeight, finalHeight)
}
func testStoreOneBlockFromEmpty() {
let initialHeight = try! compactBlockDao.latestHeight()
guard initialHeight == BlockHeight.empty() else {
XCTFail("database not empty, latest height: \(initialHeight)")
@ -62,7 +61,6 @@ class CompactBlockStorageTests: XCTestCase {
}
func testRewindTo() {
let startHeight = self.network.constants.saplingActivationHeight
let blockCount = Int(1_000)
let finalHeight = startHeight + blockCount
@ -79,10 +77,8 @@ class CompactBlockStorageTests: XCTestCase {
do {
let latestHeight = try compactBlockDao.latestHeight()
XCTAssertEqual(latestHeight, rewindHeight - 1)
} catch {
XCTFail("Rewind latest block failed with error: \(error)")
}
}
}

View File

@ -8,12 +8,15 @@
import Foundation
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable implicitly_unwrapped_optional
class DarksideSanityCheckTests: XCTestCase {
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment?
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment
// TODO: Parameterize this from environment?
// swiftlint:disable:next line_length
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
// TODO: Parameterize this from environment
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a"
let sendAmount: Int64 = 1000
var birthday: BlockHeight = 663150
let defaultLatestHeight: BlockHeight = 663175
@ -23,12 +26,12 @@ class DarksideSanityCheckTests: XCTestCase {
var expectedReorgHeight: BlockHeight = 665188
var expectedRewindHeight: BlockHeight = 665188
var network = DarksideWalletDNetwork()
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
var reorgExpectation = XCTestExpectation(description: "reorg")
let branchID = "2bb40e60"
let chainName = "main"
override func setUpWithError() throws {
try super.setUpWithError()
coordinator = try TestCoordinator(
seed: seedPhrase,
walletBirthday: birthday,
@ -37,10 +40,10 @@ class DarksideSanityCheckTests: XCTestCase {
)
try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
try coordinator.resetBlocks(dataset: .default)
}
override func tearDownWithError() throws {
try super.tearDownWithError()
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
try? FileManager.default.removeItem(at: coordinator.databases.pendingDB)
@ -54,17 +57,19 @@ class DarksideSanityCheckTests: XCTestCase {
let syncExpectation = XCTestExpectation(description: "sync to \(expectedLastBlock.height)")
try coordinator.sync(completion: { (synchronizer) in
syncExpectation.fulfill()
}, error: { (error) in
guard let e = error else {
XCTFail("failed with unknown error")
try coordinator.sync(
completion: { _ in
syncExpectation.fulfill()
},
error: { error in
guard let e = error else {
XCTFail("failed with unknown error")
return
}
XCTFail("failed with error: \(e)")
return
}
XCTFail("failed with error: \(e)")
return
})
)
wait(for: [syncExpectation], timeout: 5)
@ -75,6 +80,5 @@ class DarksideSanityCheckTests: XCTestCase {
XCTAssertEqual(firstBlock?.hash.toHexStringTxId(), expectedFirstBlock.hash)
XCTAssertEqual(lastBlock?.hash.toHexStringTxId(), expectedLastBlock.hash)
}
}

View File

@ -9,12 +9,14 @@
import XCTest
import SQLite
@testable import ZcashLightClientKit
// swiftlint:disable force_try
class DownloadOperationTests: XCTestCase {
var operationQueue = OperationQueue()
var network = ZcashNetworkBuilder.network(for: .testnet)
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
operationQueue.cancelAllOperations()
}
@ -29,13 +31,13 @@ class DownloadOperationTests: XCTestCase {
let range = activationHeight ... activationHeight + blockCount
let downloadOperation = CompactBlockDownloadOperation(downloader: downloader, range: range)
downloadOperation.completionHandler = { (finished, cancelled) in
downloadOperation.completionHandler = { finished, cancelled in
expect.fulfill()
XCTAssertTrue(finished)
XCTAssertFalse(cancelled)
}
downloadOperation.errorHandler = { (error) in
downloadOperation.errorHandler = { error in
XCTFail("Donwload Operation failed with error: \(error)")
}
@ -43,7 +45,6 @@ class DownloadOperationTests: XCTestCase {
wait(for: [expect], timeout: 10)
XCTAssertEqual(try! storage.latestHeight(),range.upperBound)
XCTAssertEqual(try! storage.latestHeight(), range.upperBound)
}
}

View File

@ -9,21 +9,21 @@
import XCTest
@testable import ZcashLightClientKit
import GRPC
// swiftlint:disable implicitly_unwrapped_optional force_unwrapping
class LightWalletServiceTests: XCTestCase {
let network: ZcashNetwork = ZcashNetworkBuilder.network(for: .testnet)
var service: LightWalletService!
var channel: Channel!
let network: ZcashNetwork = ZcashNetworkBuilder.network(for: .testnet)
override func setUp() {
// Put setup code here. This method is called before the invocation of each test method in the class.
super.setUp()
channel = ChannelProvider().channel()
service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet)
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
/// FIXME: check whether this test is stil valid on in memory lwd implementatiojn
// func testFailure() {
//
@ -44,7 +44,7 @@ class LightWalletServiceTests: XCTestCase {
let upperRange: BlockHeight = network.constants.saplingActivationHeight + count
let blockRange = lowerRange ... upperRange
service.blockRange(blockRange) { (result) in
service.blockRange(blockRange) { result in
expect.fulfill()
switch result {
case .failure(let error):
@ -73,9 +73,9 @@ class LightWalletServiceTests: XCTestCase {
}
}
func testLatestBlock(){
func testLatestBlock() {
let expect = XCTestExpectation(description: self.description)
service.latestBlockHeight { (result) in
service.latestBlockHeight { result in
expect.fulfill()
switch result {
case .failure(let e):
@ -87,5 +87,4 @@ class LightWalletServiceTests: XCTestCase {
wait(for: [expect], timeout: 10)
}
}

View File

@ -7,32 +7,30 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable force_unwrapping print_function_usage
class MemoTests: XCTestCase {
/**
Non-utf8 memos are properly ignored
*/
Non-utf8 memos are properly ignored
*/
func testNonUnicodeMemos() throws {
XCTAssertNil(Self.randomMemoData()!.asZcashTransactionMemo())
}
/**
Memo length is correct, padding characters are ignored
*/
Memo length is correct, padding characters are ignored
*/
func testMemoLength() throws {
XCTAssertEqual(validMemoData.count, 512)
XCTAssertEqual(validMemoData.asZcashTransactionMemo()!.count, Self.validMemoDataExpectedString.count)
}
/**
Verify support for common unicode characters
*/
Verify support for common unicode characters
*/
func testUnicodeCharacters() throws {
let memo = validMemoData.asZcashTransactionMemo()
XCTAssertNotNil(memo)
XCTAssertEqual(memo!, Self.validMemoDataExpectedString)
}
func testEmojiUnicodeCharacters() throws {
@ -42,32 +40,34 @@ class MemoTests: XCTestCase {
}
/**
Blank memos are ignored
*/
Blank memos are ignored
*/
func testBlankMemos() throws {
// This is an example of a functional test case.
XCTAssertNil(emptyMemoData.asZcashTransactionMemo())
}
/**
test canonical memos
*/
test canonical memos
*/
func testCanonicalBlankMemos() throws {
XCTAssertNil(Self.canonicalEmptyMemo().asZcashTransactionMemo())
}
/**
*******
* mocked memos
* ******
*/
*******
* mocked memos
* ******
*/
/**
Real text: "Here's gift from the Zec Fairy @ ECC!"
*/
Real text: "Here's gift from the Zec Fairy @ ECC!"
*/
static let validMemoDataExpectedString = "Here's gift from the Zec Fairy @ ECC!"
static let validMemoDataBase64 = "SGVyZSdzIGdpZnQgZnJvbSB0aGUgWmVjIEZhaXJ5IEAgRUNDIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
static let validMemoDataBase64 =
// swiftlint:disable:next line_length
"SGVyZSdzIGdpZnQgZnJvbSB0aGUgWmVjIEZhaXJ5IEAgRUNDIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
let validMemoData = Data(base64Encoded: validMemoDataBase64)!
@ -75,8 +75,9 @@ class MemoTests: XCTestCase {
let totallyRandomDataMemo = randomMemoData()!
static let emojiDataBase64 = "8J+SlfCfkpXwn5KV8J+mk/CfppPwn6aT8J+bofCfm6Hwn5uhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
static let emojiDataBase64 =
// swiftlint:disable:next line_length
"8J+SlfCfkpXwn5KV8J+mk/CfppPwn6aT8J+bofCfm6Hwn5uhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
static let emojiMemoData = Data(base64Encoded: emojiDataBase64)!
@ -102,4 +103,3 @@ class MemoTests: XCTestCase {
}
}
}

View File

@ -7,32 +7,31 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable implicitly_unwrapped_optional type_body_length force_unwrapping
class NetworkUpgradeTests: XCTestCase {
let activationHeight: BlockHeight = 1028500
var spendingKey = "secret-extended-key-test1qv2vf437qqqqpqpfc0arpv55ncq33p2p895hlcx0ra6d0g739v93luqdjpxun3kt050j9qnrqjyp8d7fdxgedfyxpjmuyha2ulxa6hmqvm2gnvuc3tvs3enpxwuz768qfkd286vr3jgyrgr5ddx2ukrdl95ak3tzqylzjeqw3pnmgtmwsvemrj3sk6vqgwxm9khlv46wccn33ayw52prr233ea069c9u8m3839dvw30sdf6k32xddhpte6p6qsuxval6usyh6lr55pgypkgtz"
let testRecipientAddress = "ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc" //TODO: Parameterize this from environment
let spendingKey =
// swiftlint:disable:next line_length
"secret-extended-key-test1qv2vf437qqqqpqpfc0arpv55ncq33p2p895hlcx0ra6d0g739v93luqdjpxun3kt050j9qnrqjyp8d7fdxgedfyxpjmuyha2ulxa6hmqvm2gnvuc3tvs3enpxwuz768qfkd286vr3jgyrgr5ddx2ukrdl95ak3tzqylzjeqw3pnmgtmwsvemrj3sk6vqgwxm9khlv46wccn33ayw52prr233ea069c9u8m3839dvw30sdf6k32xddhpte6p6qsuxval6usyh6lr55pgypkgtz"
// TODO: Parameterize this from environment
let testRecipientAddress = "ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc"
let sendAmount: Int64 = 1000
var birthday: BlockHeight = 1013250
let branchID = "2bb40e60"
let chainName = "main"
var birthday: BlockHeight = 1013250
var coordinator: TestCoordinator!
var network = ZcashNetworkBuilder.network(for: .testnet)
override func setUpWithError() throws {
// coordinator = try TestCoordinator(
// spendingKey: spendingKey,
// unifiedViewingKey: <#UnifiedViewingKey#>,
// walletBirthday: birthday,
// channelProvider: ChannelProvider()
// )
try super.setUpWithError()
try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
}
override func tearDownWithError() throws {
try super.tearDownWithError()
NotificationCenter.default.removeObserver(self)
try coordinator.stop()
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
@ -40,22 +39,26 @@ class NetworkUpgradeTests: XCTestCase {
try? FileManager.default.removeItem(at: coordinator.databases.pendingDB)
}
/**
Given that a wallet had funds prior to activation it can spend them after activation
*/
Given that a wallet had funds prior to activation it can spend them after activation
*/
func testSpendPriorFundsAfterActivation() throws {
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, birthday: birthday, networkActivationHeight: activationHeight, branchID: branchID, chainName: chainName, length: 15300)
try FakeChainBuilder.buildChain(
darksideWallet: coordinator.service,
birthday: birthday,
networkActivationHeight: activationHeight,
branchID: branchID,
chainName: chainName,
length: 15300
)
let firstSyncExpectation = XCTestExpectation(description: "first sync")
try coordinator.applyStaged(blockheight: activationHeight - ZcashSDK.defaultStaleTolerance)
sleep(5)
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
firstSyncExpectation.fulfill()
}, error: self.handleError)
wait(for: [firstSyncExpectation], timeout: 120)
@ -69,31 +72,40 @@ class NetworkUpgradeTests: XCTestCase {
sleep(2)
let sendExpectation = XCTestExpectation(description: "send expectation")
var p: PendingTransactionEntity? = nil
var pendingEntity: PendingTransactionEntity?
let spendAmount: Int64 = 10000
/*
send transaction to recipient address
*/
coordinator.synchronizer.sendToAddress(spendingKey: self.coordinator.spendingKeys!.first!, zatoshi: spendAmount, toAddress: self.testRecipientAddress, memo: "this is a test", from: 0, resultBlock: { (result) in
switch result {
case .failure(let e):
self.handleError(e)
case .success(let pendingTx):
p = pendingTx
send transaction to recipient address
*/
coordinator.synchronizer.sendToAddress(
spendingKey: self.coordinator.spendingKeys!.first!,
zatoshi: spendAmount,
toAddress: self.testRecipientAddress,
memo: "this is a test",
from: 0,
resultBlock: { result in
switch result {
case .failure(let e):
self.handleError(e)
case .success(let pendingTx):
pendingEntity = pendingTx
}
sendExpectation.fulfill()
}
sendExpectation.fulfill()
})
)
wait(for: [sendExpectation], timeout: 11)
guard let _ = p else {
guard pendingEntity != nil else {
XCTFail("no pending transaction after sending")
try coordinator.stop()
return
}
/*
getIncomingTransaction
*/
getIncomingTransaction
*/
guard let incomingTx = try coordinator.getIncomingTransactions()?.first else {
XCTFail("no incoming transaction")
try coordinator.stop()
@ -103,45 +115,44 @@ class NetworkUpgradeTests: XCTestCase {
let sentTxHeight: BlockHeight = activationHeight + 2
/*
stage transaction at sentTxHeight
*/
stage transaction at sentTxHeight
*/
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
try coordinator.applyStaged(blockheight: activationHeight + 20)
sleep(1)
let afterSendExpectation = XCTestExpectation(description: "aftersend")
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
afterSendExpectation.fulfill()
}, error: self.handleError)
wait(for: [afterSendExpectation], timeout: 10)
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), verifiedBalance - spendAmount)
}
/**
Given that a wallet receives funds after activation it can spend them when confirmed
*/
Given that a wallet receives funds after activation it can spend them when confirmed
*/
func testSpendPostActivationFundsAfterConfirmation() throws {
try FakeChainBuilder.buildChainPostActivationFunds(darksideWallet: coordinator.service, birthday: birthday, networkActivationHeight: activationHeight, length: 15300)
try FakeChainBuilder.buildChainPostActivationFunds(
darksideWallet: coordinator.service,
birthday: birthday,
networkActivationHeight: activationHeight,
length: 15300
)
let firstSyncExpectation = XCTestExpectation(description: "first sync")
try coordinator.applyStaged(blockheight: activationHeight + 10)
sleep(3)
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
firstSyncExpectation.fulfill()
}, error: self.handleError)
wait(for: [firstSyncExpectation], timeout: 120)
guard try coordinator.synchronizer.allReceivedTransactions().filter({$0.minedHeight > activationHeight}).count > 0 else {
guard try !coordinator.synchronizer.allReceivedTransactions().filter({ $0.minedHeight > activationHeight }).isEmpty else {
XCTFail("this test requires funds received after activation height")
return
}
@ -149,26 +160,33 @@ class NetworkUpgradeTests: XCTestCase {
try coordinator.applyStaged(blockheight: activationHeight + 20)
sleep(2)
let sendExpectation = XCTestExpectation(description: "send expectation")
var p: PendingTransactionEntity? = nil
var pendingEntity: PendingTransactionEntity?
let spendAmount: Int64 = 10000
/*
send transaction to recipient address
*/
coordinator.synchronizer.sendToAddress(spendingKey: self.coordinator.spendingKeys!.first!, zatoshi: spendAmount, toAddress: self.testRecipientAddress, memo: "this is a test", from: 0, resultBlock: { (result) in
switch result {
case .failure(let e):
self.handleError(e)
case .success(let pendingTx):
p = pendingTx
send transaction to recipient address
*/
coordinator.synchronizer.sendToAddress(
spendingKey: self.coordinator.spendingKeys!.first!,
zatoshi: spendAmount,
toAddress: self.testRecipientAddress,
memo: "this is a test",
from: 0,
resultBlock: { result in
switch result {
case .failure(let e):
self.handleError(e)
case .success(let pendingTx):
pendingEntity = pendingTx
}
sendExpectation.fulfill()
}
sendExpectation.fulfill()
})
)
wait(for: [sendExpectation], timeout: 11)
guard let _ = p else {
guard pendingEntity != nil else {
XCTFail("no pending transaction after sending")
try coordinator.stop()
return
@ -178,66 +196,74 @@ class NetworkUpgradeTests: XCTestCase {
let afterSendExpectation = XCTestExpectation(description: "aftersend")
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
afterSendExpectation.fulfill()
}, error: self.handleError)
wait(for: [afterSendExpectation], timeout: 10)
}
/**
Given that a wallet sends funds some between (activation - expiry_height) and activation, those funds are shown as sent if mined.
*/
/**
Given that a wallet sends funds some between (activation - expiry_height) and activation, those funds are shown as sent if mined.
*/
func testSpendMinedSpendThatExpiresOnActivation() throws {
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, birthday: birthday, networkActivationHeight: activationHeight, branchID: branchID, chainName: chainName, length: 15300)
try FakeChainBuilder.buildChain(
darksideWallet: coordinator.service,
birthday: birthday,
networkActivationHeight: activationHeight,
branchID: branchID,
chainName: chainName,
length: 15300
)
let firstSyncExpectation = XCTestExpectation(description: "first sync")
try coordinator.applyStaged(blockheight: activationHeight - 10)
sleep(3)
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
firstSyncExpectation.fulfill()
}, error: self.handleError)
wait(for: [firstSyncExpectation], timeout: 120)
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: activationHeight))
let sendExpectation = XCTestExpectation(description: "send expectation")
var p: PendingTransactionEntity? = nil
var pendingEntity: PendingTransactionEntity?
let spendAmount: Int64 = 10000
/*
send transaction to recipient address
*/
coordinator.synchronizer.sendToAddress(spendingKey: self.coordinator.spendingKeys!.first!, zatoshi: spendAmount, toAddress: self.testRecipientAddress, memo: "this is a test", from: 0, resultBlock: { (result) in
switch result {
case .failure(let e):
self.handleError(e)
case .success(let pendingTx):
p = pendingTx
send transaction to recipient address
*/
coordinator.synchronizer.sendToAddress(
spendingKey: self.coordinator.spendingKeys!.first!,
zatoshi: spendAmount,
toAddress: self.testRecipientAddress,
memo: "this is a test",
from: 0,
resultBlock: { result in
switch result {
case .failure(let e):
self.handleError(e)
case .success(let pendingTx):
pendingEntity = pendingTx
}
sendExpectation.fulfill()
}
sendExpectation.fulfill()
})
)
wait(for: [sendExpectation], timeout: 11)
guard let pendingTx = p else {
guard let pendingTx = pendingEntity else {
XCTFail("no pending transaction after sending")
try coordinator.stop()
return
}
/*
getIncomingTransaction
*/
getIncomingTransaction
*/
guard let incomingTx = try coordinator.getIncomingTransactions()?.first else {
XCTFail("no incoming transaction")
try coordinator.stop()
@ -246,12 +272,9 @@ class NetworkUpgradeTests: XCTestCase {
let sentTxHeight: BlockHeight = activationHeight - 5
/*
stage transaction at sentTxHeight
*/
stage transaction at sentTxHeight
*/
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
try coordinator.applyStaged(blockheight: activationHeight + 5)
@ -259,15 +282,16 @@ class NetworkUpgradeTests: XCTestCase {
let afterSendExpectation = XCTestExpectation(description: "aftersend")
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
afterSendExpectation.fulfill()
}, error: self.handleError)
wait(for: [afterSendExpectation], timeout: 10)
guard let confirmedTx = try coordinator.synchronizer.allConfirmedTransactions(from: nil, limit: Int.max)?.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) else {
guard
let confirmedTx = try coordinator.synchronizer.allConfirmedTransactions(from: nil, limit: Int.max)?
.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
else {
XCTFail("the sent transaction is not listed as a confirmed transaction")
return
}
@ -276,11 +300,17 @@ class NetworkUpgradeTests: XCTestCase {
}
/**
Given that a wallet sends funds somewhere between (activation - expiry_height) and activation, those funds are available if expired after expiration height.
*/
Given that a wallet sends funds somewhere between (activation - expiry_height) and activation, those funds are available if expired after expiration height.
*/
func testExpiredSpendAfterActivation() throws {
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, birthday: birthday, networkActivationHeight: activationHeight, branchID: branchID, chainName: chainName, length: 15300)
try FakeChainBuilder.buildChain(
darksideWallet: coordinator.service,
birthday: birthday,
networkActivationHeight: activationHeight,
branchID: branchID,
chainName: chainName,
length: 15300
)
let firstSyncExpectation = XCTestExpectation(description: "first sync")
let offset = 5
@ -289,10 +319,8 @@ class NetworkUpgradeTests: XCTestCase {
let verifiedBalancePreActivation = coordinator.synchronizer.initializer.getVerifiedBalance()
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
firstSyncExpectation.fulfill()
}, error: self.handleError)
wait(for: [firstSyncExpectation], timeout: 120)
@ -303,57 +331,64 @@ class NetworkUpgradeTests: XCTestCase {
}
let sendExpectation = XCTestExpectation(description: "send expectation")
var p: PendingTransactionEntity? = nil
var pendingEntity: PendingTransactionEntity?
let spendAmount: Int64 = 10000
/*
send transaction to recipient address
*/
coordinator.synchronizer.sendToAddress(spendingKey: self.coordinator.spendingKeys!.first!, zatoshi: spendAmount, toAddress: self.testRecipientAddress, memo: "this is a test", from: 0, resultBlock: { (result) in
switch result {
case .failure(let e):
self.handleError(e)
case .success(let pendingTx):
p = pendingTx
send transaction to recipient address
*/
coordinator.synchronizer.sendToAddress(
spendingKey: self.coordinator.spendingKeys!.first!,
zatoshi: spendAmount,
toAddress: self.testRecipientAddress,
memo: "this is a test",
from: 0,
resultBlock: { result in
switch result {
case .failure(let e):
self.handleError(e)
case .success(let pendingTx):
pendingEntity = pendingTx
}
sendExpectation.fulfill()
}
sendExpectation.fulfill()
})
)
wait(for: [sendExpectation], timeout: 11)
guard let pendingTx = p else {
guard let pendingTx = pendingEntity else {
XCTFail("no pending transaction after sending")
try coordinator.stop()
return
}
/*
getIncomingTransaction
*/
guard let _ = try coordinator.getIncomingTransactions()?.first else {
getIncomingTransaction
*/
guard try coordinator.getIncomingTransactions()?.first != nil else {
XCTFail("no incoming transaction")
try coordinator.stop()
return
}
/*
don't stage transaction
*/
don't stage transaction
*/
try coordinator.applyStaged(blockheight: activationHeight + offset)
sleep(2)
let afterSendExpectation = XCTestExpectation(description: "aftersend")
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
afterSendExpectation.fulfill()
}, error: self.handleError)
wait(for: [afterSendExpectation], timeout: 10)
guard try coordinator.synchronizer.allConfirmedTransactions(from: nil, limit: Int.max)?.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) == nil else {
guard
try coordinator.synchronizer.allConfirmedTransactions(from: nil, limit: Int.max)?
.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId }) == nil
else {
XCTFail("the sent transaction should not be not listed as a confirmed transaction")
return
}
@ -362,20 +397,25 @@ class NetworkUpgradeTests: XCTestCase {
}
/**
Given that a wallet has notes both received prior and after activation these can be combined to supply a larger amount spend.
*/
Given that a wallet has notes both received prior and after activation these can be combined to supply a larger amount spend.
*/
func testCombinePreActivationNotesAndPostActivationNotesOnSpend() throws {
try FakeChainBuilder.buildChainMixedFunds(darksideWallet: coordinator.service, birthday: birthday, networkActivationHeight: activationHeight, branchID: branchID, chainName: chainName, length: 15300)
try FakeChainBuilder.buildChainMixedFunds(
darksideWallet: coordinator.service,
birthday: birthday,
networkActivationHeight: activationHeight,
branchID: branchID,
chainName: chainName,
length: 15300
)
let firstSyncExpectation = XCTestExpectation(description: "first sync")
try coordinator.applyStaged(blockheight: activationHeight - 1)
sleep(3)
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
firstSyncExpectation.fulfill()
}, error: self.handleError)
wait(for: [firstSyncExpectation], timeout: 120)
@ -386,14 +426,12 @@ class NetworkUpgradeTests: XCTestCase {
sleep(2)
let secondSyncExpectation = XCTestExpectation(description: "second sync")
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
secondSyncExpectation.fulfill()
}, error: self.handleError)
wait(for: [secondSyncExpectation], timeout: 10)
guard try coordinator.synchronizer.allReceivedTransactions().filter({$0.minedHeight > activationHeight}).count > 0 else {
guard try !coordinator.synchronizer.allReceivedTransactions().filter({ $0.minedHeight > activationHeight }).isEmpty else {
XCTFail("this test requires funds received after activation height")
return
}
@ -401,27 +439,34 @@ class NetworkUpgradeTests: XCTestCase {
XCTAssertTrue(preActivationBalance < postActivationBalance, "This test requires that funds post activation are greater that pre activation")
let sendExpectation = XCTestExpectation(description: "send expectation")
var p: PendingTransactionEntity? = nil
var pendingEntity: PendingTransactionEntity?
// spend all the funds
let spendAmount: Int64 = postActivationBalance - Int64(network.constants.defaultFee(for: activationHeight))
/*
send transaction to recipient address
*/
coordinator.synchronizer.sendToAddress(spendingKey: self.coordinator.spendingKeys!.first!, zatoshi: spendAmount, toAddress: self.testRecipientAddress, memo: "this is a test", from: 0, resultBlock: { (result) in
switch result {
case .failure(let e):
self.handleError(e)
case .success(let pendingTx):
p = pendingTx
send transaction to recipient address
*/
coordinator.synchronizer.sendToAddress(
spendingKey: self.coordinator.spendingKeys!.first!,
zatoshi: spendAmount,
toAddress: self.testRecipientAddress,
memo: "this is a test",
from: 0,
resultBlock: { result in
switch result {
case .failure(let e):
self.handleError(e)
case .success(let pendingTx):
pendingEntity = pendingTx
}
sendExpectation.fulfill()
}
sendExpectation.fulfill()
})
)
wait(for: [sendExpectation], timeout: 15)
guard let _ = p else {
guard pendingEntity != nil else {
XCTFail("no pending transaction after sending")
try coordinator.stop()
return

View File

@ -8,16 +8,19 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable implicitly_unwrapped_optional
class NotesRepositoryTests: XCTestCase {
var sentNotesRepository: SentNotesRepository!
var receivedNotesRepository: ReceivedNoteRepository!
override func setUp() {
super.setUp()
sentNotesRepository = TestDbBuilder.sentNotesRepository()
receivedNotesRepository = TestDbBuilder.receivedNotesRepository()
}
override func tearDown() {
super.tearDown()
sentNotesRepository = nil
receivedNotesRepository = nil
}
@ -32,6 +35,5 @@ class NotesRepositoryTests: XCTestCase {
var count: Int?
XCTAssertNoThrow(try { count = try receivedNotesRepository.count() }())
XCTAssertEqual(count, 27)
}
}

View File

@ -7,19 +7,24 @@
import XCTest
@testable import ZcashLightClientKit
class NullBytesTests: XCTestCase {
let networkType = NetworkType.mainnet
func testZaddrNullBytes() throws {
let validZaddr = "zs1gqtfu59z20s9t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp" // this is a valid zAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/
let ZaddrWithNullBytes = "\(validZaddr)\0something else that makes the address invalid"
// this is a valid zAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/
let validZaddr = "zs1gqtfu59z20s9t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp"
let zAddrWithNullBytes = "\(validZaddr)\0something else that makes the address invalid"
XCTAssertFalse(try ZcashRustBackend.isValidShieldedAddress(ZaddrWithNullBytes, networkType: networkType))
XCTAssertFalse(try ZcashRustBackend.isValidShieldedAddress(zAddrWithNullBytes, networkType: networkType))
}
func testTaddrNullBytes() throws {
let validTAddr = "t1J5pTRzJi7j8Xw9VJTrPxPEkaigr69gKVT" // this is a valid tAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/
let TaddrWithNullBytes = "\(validTAddr)\0fasdfasdf"
XCTAssertFalse(try ZcashRustBackend.isValidTransparentAddress(TaddrWithNullBytes, networkType: networkType))
// this is a valid tAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/
let validTAddr = "t1J5pTRzJi7j8Xw9VJTrPxPEkaigr69gKVT"
let tAddrWithNullBytes = "\(validTAddr)\0fasdfasdf"
XCTAssertFalse(try ZcashRustBackend.isValidTransparentAddress(tAddrWithNullBytes, networkType: networkType))
}
func testInitAccountTableNullBytes() throws {
@ -27,11 +32,24 @@ class NullBytesTests: XCTestCase {
let goodHash = "00000000015c597fab53f58b9e1ededbe8bd83ca0203788e2039eceeb0d65ca6"
let time: UInt32 = 1582235356
let height: Int32 = 735000
// swiftlint:disable:next line_length
let wrongTree = "0161f2ff97ff6ac6a90f9bce76c11710460f4944d8695aecc7dc99e34cad0131040011015325b185e23e82562db27817be996ffade9597181244f67efc40561aeb9dde1101daeffadc9e38f755bcb55a847a1278518a0ba4a2ef33b2fe01bbb3eb242ab0070000000000011c51f9077e3f7e28e8e337eaf4bb99b41acbc853a37dcc1e172467a1c919fe4100010bb1f55481b2268ef31997dc0fb6b48a530bc17870220f156d832326c433eb0a010b3768d3bf7868a67823e022f49be67982d0588e7041c498a756024\0750065a4a0001a9e1bf4bccb48b14b544e770f21d48f2d3ad8d6ca54eccc92f60634e3078eb48013a1f7fb005388ac6f04099b647ed85d8b025d8ae4b178c2376b473b121b8c052000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
// swiftlint:disable:next line_length
let goodTree = "0161f2ff97ff6ac6a90f9bce76c11710460f4944d8695aecc7dc99e34cad0131040011015325b185e23e82562db27817be996ffade9597181244f67efc40561aeb9dde1101daeffadc9e38f755bcb55a847a1278518a0ba4a2ef33b2fe01bbb3eb242ab0070000000000011c51f9077e3f7e28e8e337eaf4bb99b41acbc853a37dcc1e172467a1c919fe4100010bb1f55481b2268ef31997dc0fb6b48a530bc17870220f156d832326c433eb0a010b3768d3bf7868a67823e022f49be67982d0588e7041c498a756024750065a4a0001a9e1bf4bccb48b14b544e770f21d48f2d3ad8d6ca54eccc92f60634e3078eb48013a1f7fb005388ac6f04099b647ed85d8b025d8ae4b178c2376b473b121b8c052000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
XCTAssertThrowsError(try ZcashRustBackend.initBlocksTable(dbData: __dataDbURL(), height: height , hash: wrongHash, time: time, saplingTree: goodTree, networkType: networkType), "InitBlocksTable with Null bytes on hash string should have failed") { (error) in
XCTAssertThrowsError(
try ZcashRustBackend.initBlocksTable(
dbData: __dataDbURL(),
height: height,
hash: wrongHash,
time: time,
saplingTree: goodTree,
networkType: networkType
),
"InitBlocksTable with Null bytes on hash string should have failed"
) { error in
guard let rustError = error as? RustWeldingError else {
XCTFail("Expected RustWeldingError")
return
@ -45,8 +63,17 @@ class NullBytesTests: XCTestCase {
}
}
XCTAssertThrowsError(try ZcashRustBackend.initBlocksTable(dbData: __dataDbURL(), height: height , hash: goodHash, time: time, saplingTree: wrongTree, networkType: networkType), "InitBlocksTable with Null bytes on saplingTree string should have failed") { (error) in
XCTAssertThrowsError(
try ZcashRustBackend.initBlocksTable(
dbData: __dataDbURL(),
height: height,
hash: goodHash,
time: time,
saplingTree: wrongTree,
networkType: networkType
),
"InitBlocksTable with Null bytes on saplingTree string should have failed"
) { error in
guard let rustError = error as? RustWeldingError else {
XCTFail("Expected RustWeldingError")
return
@ -62,12 +89,16 @@ class NullBytesTests: XCTestCase {
}
func testderiveExtendedFullViewingKeyWithNullBytes() throws {
let wrongSpendingKeys = "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mq\0uy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv" //this spending key corresponds to the "demo app reference seed"
// swiftlint:disable:next line_length
let wrongSpendingKeys = "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mq\0uy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv" // this spending key corresponds to the "demo app reference seed"
// swiftlint:disable:next line_length
let goodSpendingKeys = "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mquy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv"
XCTAssertThrowsError(try ZcashRustBackend.deriveExtendedFullViewingKey(wrongSpendingKeys, networkType: networkType),"Should have thrown an error but didn't! this is dangerous!") { (error) in
XCTAssertThrowsError(
try ZcashRustBackend.deriveExtendedFullViewingKey(wrongSpendingKeys, networkType: networkType),
"Should have thrown an error but didn't! this is dangerous!"
) { error in
guard let rustError = error as? RustWeldingError else {
XCTFail("Expected RustWeldingError")
return
@ -82,15 +113,17 @@ class NullBytesTests: XCTestCase {
}
XCTAssertNoThrow(try ZcashRustBackend.deriveExtendedFullViewingKey(goodSpendingKeys, networkType: networkType))
}
func testCheckNullBytes() throws {
let validZaddr = "zs1gqtfu59z20s9t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp" // this is a valid zAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/
// this is a valid zAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/
let validZaddr = "zs1gqtfu59z20s9t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp"
XCTAssertFalse(validZaddr.containsCStringNullBytesBeforeStringEnding())
XCTAssertTrue("zs1gqtfu59z20s\09t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp".containsCStringNullBytesBeforeStringEnding())
XCTAssertTrue(
"zs1gqtfu59z20s\09t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp"
.containsCStringNullBytesBeforeStringEnding()
)
XCTAssertTrue("\0".containsCStringNullBytesBeforeStringEnding())
XCTAssertFalse("".containsCStringNullBytesBeforeStringEnding())
}

View File

@ -7,13 +7,20 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable implicitly_unwrapped_optional
class PagedTransactionRepositoryTests: XCTestCase {
var pagedTransactionRepository: PaginatedTransactionRepository!
var transactionRepository: TransactionRepository!
override func setUp() {
transactionRepository = MockTransactionRepository(unminedCount: 5, receivedCount: 150, sentCount: 100, network: ZcashNetworkBuilder.network(for: .testnet))
super.setUp()
transactionRepository = MockTransactionRepository(
unminedCount: 5,
receivedCount: 150,
sentCount: 100,
network: ZcashNetworkBuilder.network(for: .testnet)
)
pagedTransactionRepository = PagedTransactionDAO(repository: transactionRepository)
}
@ -21,18 +28,18 @@ class PagedTransactionRepositoryTests: XCTestCase {
let pageSize = pagedTransactionRepository.pageSize
let pageCount = pagedTransactionRepository.pageCount
let totalItems = pagedTransactionRepository.itemCount
for i in 0 ..< pageCount/pageSize {
guard let page = try? pagedTransactionRepository.page(i) else {
XCTFail("page failed to get page \(i)")
for index in 0 ..< pageCount / pageSize {
guard let page = try? pagedTransactionRepository.page(index) else {
XCTFail("page failed to get page \(index)")
return
}
if i < pageCount {
if index < pageCount {
XCTAssert(page.count == pageSize)
} else {
// last page has to have the remainding items
XCTAssertEqual(page.count, totalItems - (pageSize * pageCount))
XCTAssertEqual(page.count, totalItems - (pageSize * pageCount))
}
}
}
}

View File

@ -7,22 +7,24 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable force_try force_unwrapping implicitly_unwrapped_optional
class PendingTransactionRepositoryTests: XCTestCase {
var pendingRepository: PendingTransactionRepository!
let dbUrl = try! TestDbBuilder.pendingTransactionsDbURL()
let recipientAddress = "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6"
var pendingRepository: PendingTransactionRepository!
override func setUp() {
super.setUp()
cleanUpDb()
let dao = PendingTransactionSQLDAO(dbProvider: SimpleConnectionProvider(path: try! TestDbBuilder.pendingTransactionsDbURL().absoluteString))
try! dao.createrTableIfNeeded()
pendingRepository = dao
}
override func tearDown() {
super.tearDown()
cleanUpDb()
}
@ -31,77 +33,79 @@ class PendingTransactionRepositoryTests: XCTestCase {
}
func testCreate() {
let transaction = createAndStoreMockedTransaction()
let tx = createAndStoreMockedTransaction()
guard let id = tx.id, id >= 0 else {
guard let id = transaction.id, id >= 0 else {
XCTFail("failed to create mocked transaction that was just inserted")
return
}
var expectedTx: PendingTransactionEntity?
XCTAssertNoThrow(try { expectedTx = try pendingRepository.find(by: id)}())
XCTAssertNoThrow(try { expectedTx = try pendingRepository.find(by: id) }())
guard let expected = expectedTx else {
XCTFail("failed to retrieve mocked transaction by id \(id) that was just inserted")
return
}
XCTAssertEqual(tx.accountIndex, expected.accountIndex)
XCTAssertEqual(tx.value, expected.value)
XCTAssertEqual(tx.toAddress, expected.toAddress)
XCTAssertEqual(transaction.accountIndex, expected.accountIndex)
XCTAssertEqual(transaction.value, expected.value)
XCTAssertEqual(transaction.toAddress, expected.toAddress)
}
func testFindById() {
let tx = createAndStoreMockedTransaction()
let transaction = createAndStoreMockedTransaction()
var expected: PendingTransactionEntity?
guard let id = tx.id else {
guard let id = transaction.id else {
XCTFail("transaction with no id")
return
}
XCTAssertNoThrow(try { expected = try pendingRepository.find(by: id)}())
XCTAssertNoThrow(try { expected = try pendingRepository.find(by: id) }())
XCTAssertNotNil(expected)
}
func testCancel() {
let tx = createAndStoreMockedTransaction()
guard let id = tx.id else {
XCTFail("transaction with no id")
return
}
let transaction = createAndStoreMockedTransaction()
guard let id = transaction.id else {
XCTFail("transaction with no id")
return
}
guard id >= 0 else {
XCTFail("failed to create mocked transaction that was just inserted")
return
}
XCTAssertNoThrow(try pendingRepository.cancel(tx))
XCTAssertNoThrow(try pendingRepository.cancel(transaction))
}
func testDelete() {
let tx = createAndStoreMockedTransaction()
guard let id = tx.id else {
XCTFail("transaction with no id")
return
}
let transaction = createAndStoreMockedTransaction()
guard let id = transaction.id else {
XCTFail("transaction with no id")
return
}
guard id >= 0 else {
XCTFail("failed to create mocked transaction that was just inserted")
return
}
XCTAssertNoThrow(try pendingRepository.delete(tx))
XCTAssertNoThrow(try pendingRepository.delete(transaction))
var unexpectedTx: PendingTransactionEntity?
XCTAssertNoThrow(try { unexpectedTx = try pendingRepository.find(by: id) }())
XCTAssertNil(unexpectedTx)
}
func testGetAll() {
var mockTransactions = [PendingTransactionEntity]()
var mockTransactions: [PendingTransactionEntity] = []
for _ in 1...100 {
mockTransactions.append(createAndStoreMockedTransaction())
}
@ -116,20 +120,21 @@ class PendingTransactionRepositoryTests: XCTestCase {
}
XCTAssertEqual(mockTransactions.count, allTxs.count)
}
func testUpdate() {
let newAccountIndex = 1
let newValue: Int = 123_456
let tx = createAndStoreMockedTransaction()
guard let id = tx.id else {
XCTFail("transaction with no id")
return
}
let transaction = createAndStoreMockedTransaction()
guard let id = transaction.id else {
XCTFail("transaction with no id")
return
}
var stored: PendingTransactionEntity?
XCTAssertNoThrow(try { stored = try pendingRepository.find(by: id)}())
XCTAssertNoThrow(try { stored = try pendingRepository.find(by: id) }())
guard stored != nil else {
XCTFail("failed to store tx")
@ -152,12 +157,12 @@ class PendingTransactionRepositoryTests: XCTestCase {
}
func createAndStoreMockedTransaction() -> PendingTransactionEntity {
var tx = mockTransaction()
var transaction = mockTransaction()
var id: Int?
XCTAssertNoThrow(try { id = try pendingRepository.create(tx) }())
tx.id = Int(id ?? -1)
return tx
XCTAssertNoThrow(try { id = try pendingRepository.create(transaction) }())
transaction.id = Int(id ?? -1)
return transaction
}
func testPerformanceExample() {
@ -170,5 +175,4 @@ class PendingTransactionRepositoryTests: XCTestCase {
private func mockTransaction() -> PendingTransactionEntity {
PendingTransaction(value: Int.random(in: 1 ... 1_000_000), toAddress: recipientAddress, memo: nil, account: 0)
}
}

View File

@ -7,10 +7,14 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable implicitly_unwrapped_optional
class PendingTransactionUpdatesTest: XCTestCase {
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment?
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment
// TODO: Parameterize this from environment?
// swiftlint:disable:next line_length
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
// TODO: Parameterize this from environment
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a"
let sendAmount: Int64 = 1000
var birthday: BlockHeight = 663150
@ -20,12 +24,12 @@ class PendingTransactionUpdatesTest: XCTestCase {
var sentTransactionExpectation = XCTestExpectation(description: "sent")
var expectedReorgHeight: BlockHeight = 665188
var expectedRewindHeight: BlockHeight = 665188
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
var reorgExpectation = XCTestExpectation(description: "reorg")
let branchID = "2bb40e60"
let chainName = "main"
let network = DarksideWalletDNetwork()
override func setUpWithError() throws {
try super.setUpWithError()
coordinator = try TestCoordinator(
seed: seedPhrase,
walletBirthday: birthday,
@ -36,6 +40,7 @@ class PendingTransactionUpdatesTest: XCTestCase {
}
override func tearDownWithError() throws {
try super.tearDownWithError()
NotificationCenter.default.removeObserver(self)
try coordinator.stop()
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
@ -44,23 +49,21 @@ class PendingTransactionUpdatesTest: XCTestCase {
}
@objc func handleReorg(_ notification: Notification) {
guard let reorgHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight
// let rewindHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight
else {
XCTFail("empty reorg notification")
return
guard
let reorgHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight
else {
XCTFail("empty reorg notification")
return
}
// XCTAssertEqual(rewindHeight, expectedRewindHeight)
XCTAssertEqual(reorgHeight, expectedReorgHeight)
reorgExpectation.fulfill()
}
func testPendingTransactionMinedHeightUpdated() throws {
/*
1. create fake chain
*/
1. create fake chain
*/
LoggerProxy.info("1. create fake chain")
try FakeChainBuilder.buildChain(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName)
@ -69,13 +72,12 @@ class PendingTransactionUpdatesTest: XCTestCase {
sleep(2)
let firstSyncExpectation = XCTestExpectation(description: "first sync")
/*
1a. sync to latest height
*/
1a. sync to latest height
*/
LoggerProxy.info("1a. sync to latest height")
try coordinator.sync(completion: { (s) in
try coordinator.sync(completion: { _ in
firstSyncExpectation.fulfill()
}, error: self.handleError)
@ -84,37 +86,55 @@ class PendingTransactionUpdatesTest: XCTestCase {
sleep(1)
let sendExpectation = XCTestExpectation(description: "send expectation")
var p: PendingTransactionEntity? = nil
var pendingEntity: PendingTransactionEntity?
/*
2. send transaction to recipient address
*/
2. send transaction to recipient address
*/
LoggerProxy.info("2. send transaction to recipient address")
coordinator.synchronizer.sendToAddress(spendingKey: self.coordinator.spendingKeys!.first!, zatoshi: 20000, toAddress: self.testRecipientAddress, memo: "this is a test", from: 0, resultBlock: { (result) in
switch result {
case .failure(let e):
self.handleError(e)
case .success(let pendingTx):
p = pendingTx
coordinator.synchronizer.sendToAddress(
// swiftlint:disable:next force_unwrapping
spendingKey: self.coordinator.spendingKeys!.first!,
zatoshi: 20000,
toAddress: self.testRecipientAddress,
memo: "this is a test",
from: 0,
resultBlock: { result in
switch result {
case .failure(let e):
self.handleError(e)
case .success(let pendingTx):
pendingEntity = pendingTx
}
sendExpectation.fulfill()
}
sendExpectation.fulfill()
})
)
wait(for: [sendExpectation], timeout: 11)
guard let pendingUnconfirmedTx = p else {
guard let pendingUnconfirmedTx = pendingEntity else {
XCTFail("no pending transaction after sending")
try coordinator.stop()
return
}
XCTAssertFalse(pendingUnconfirmedTx.isConfirmed(currentHeight: 663188), "pending transaction evaluated as confirmed when it shouldn't")
XCTAssertFalse(pendingUnconfirmedTx.isMined, "pending transaction evaluated as mined when it shouldn't")
XCTAssertFalse(
pendingUnconfirmedTx.isConfirmed(currentHeight: 663188),
"pending transaction evaluated as confirmed when it shouldn't"
)
XCTAssertFalse(
pendingUnconfirmedTx.isMined,
"pending transaction evaluated as mined when it shouldn't"
)
XCTAssertTrue(pendingUnconfirmedTx.isPending(currentHeight: 663188), "pending transaction evaluated as not pending when it should be")
XCTAssertTrue(
pendingUnconfirmedTx.isPending(currentHeight: 663188),
"pending transaction evaluated as not pending when it should be"
)
/**
3. getIncomingTransaction
*/
3. getIncomingTransaction
*/
LoggerProxy.info("3. getIncomingTransaction")
guard let incomingTx = try coordinator.getIncomingTransactions()?.first else {
XCTFail("no incoming transaction")
@ -124,31 +144,34 @@ class PendingTransactionUpdatesTest: XCTestCase {
let sentTxHeight: BlockHeight = 663189
/*
4. stage transaction at sentTxHeight
*/
4. stage transaction at sentTxHeight
*/
LoggerProxy.info("4. stage transaction at \(sentTxHeight)")
try coordinator.stageBlockCreate(height: sentTxHeight)
try coordinator.stageTransaction(incomingTx, at: sentTxHeight)
/*
5. applyHeight(sentTxHeight)
*/
5. applyHeight(sentTxHeight)
*/
LoggerProxy.info("5. applyHeight(\(sentTxHeight))")
try coordinator.applyStaged(blockheight: sentTxHeight)
sleep(2)
/*
6. sync to latest height
*/
6. sync to latest height
*/
LoggerProxy.info("6. sync to latest height")
let secondSyncExpectation = XCTestExpectation(description: "after send expectation")
let secondSyncExpectation = XCTestExpectation(description: "after send expectation")
try coordinator.sync(completion: { (s) in
secondSyncExpectation.fulfill()
}, error: self.handleError)
try coordinator.sync(
completion: { _ in
secondSyncExpectation.fulfill()
},
error: self.handleError
)
wait(for: [secondSyncExpectation], timeout: 5)
@ -158,16 +181,16 @@ class PendingTransactionUpdatesTest: XCTestCase {
}
/*
6a. verify that there's a pending transaction with a mined height of sentTxHeight
*/
6a. verify that there's a pending transaction with a mined height of sentTxHeight
*/
LoggerProxy.info("6a. verify that there's a pending transaction with a mined height of \(sentTxHeight)")
XCTAssertEqual(afterStagePendingTx.minedHeight, sentTxHeight)
XCTAssertTrue(afterStagePendingTx.isMined, "pending transaction shown as unmined when it has been mined")
XCTAssertTrue(afterStagePendingTx.isPending(currentHeight: sentTxHeight))
/*
7. stage 15 blocks from sentTxHeight
*/
7. stage 15 blocks from sentTxHeight
*/
LoggerProxy.info("7. stage 15 blocks from \(sentTxHeight)")
try coordinator.stageBlockCreate(height: sentTxHeight + 1, count: 15)
sleep(2)
@ -183,20 +206,18 @@ class PendingTransactionUpdatesTest: XCTestCase {
*/
LoggerProxy.info("last sync to latest height: \(lastStageHeight)")
try coordinator.sync(completion: { (s) in
try coordinator.sync(completion: { _ in
syncToConfirmExpectation.fulfill()
}, error: self.handleError)
wait(for: [syncToConfirmExpectation], timeout: 6)
var supposedlyPendingUnexistingTransaction: PendingTransactionEntity? = nil
var supposedlyPendingUnexistingTransaction: PendingTransactionEntity?
XCTAssertNoThrow(try { supposedlyPendingUnexistingTransaction = try coordinator.synchronizer.allPendingTransactions().first }())
XCTAssertNil(supposedlyPendingUnexistingTransaction)
}
func handleError(_ error: Error?) {
_ = try? coordinator.stop()
guard let testError = error else {
@ -207,6 +228,11 @@ class PendingTransactionUpdatesTest: XCTestCase {
}
func hookToReOrgNotification() {
NotificationCenter.default.addObserver(self, selector: #selector(handleReorg(_:)), name: .blockProcessorHandledReOrg, object: nil)
NotificationCenter.default.addObserver(
self,
selector: #selector(handleReorg(_:)),
name: .blockProcessorHandledReOrg,
object: nil
)
}
}

View File

@ -8,29 +8,35 @@
import XCTest
@testable import ZcashLightClientKit
@testable import SwiftProtobuf
// swiftlint:disable implicitly_unwrapped_optional
class RawTransactionTests: XCTestCase {
var rawTx: Data!
var transactionRepository: TransactionSQLDAO!
override func setUp() {
super.setUp()
rawTx = Data(base64Encoded: txBase64String)
}
func testDeserialize() {
guard let raw = Data(base64Encoded: txFromAndroidSDK) else {
XCTFail("no raw data")
return
}
let rawTransaction = RawTransaction.with({ (r) in
r.data = raw
let rawTransaction = RawTransaction.with({ rawTr in
rawTr.data = raw
})
XCTAssertNotNil(rawTransaction)
}
let txFromAndroidSDK =
// swiftlint:disable:next line_length
"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"
let txFromAndroidSDK = "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"
let txBase64String = "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"
let txBase64String =
// swiftlint:disable:next line_length
"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"
}

View File

@ -7,61 +7,69 @@
import XCTest
@testable import ZcashLightClientKit
/**
basic reorg test. Scan, get a reorg and then reach latest height.
* connect to dLWD
* request latest height -> receive 663250
* download and sync blocks from 663150 to 663250
* trigger reorg by calling API (no need to pass params)**
* request latest height -> receive 663251!
* download that block
* observe that the prev hash of that block does not match the hash that we have for 663250
* rewind 10 blocks and request blocks 663241 to 663251
*/
class ReOrgTests: XCTestCase {
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment?
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment
/**
basic reorg test. Scan, get a reorg and then reach latest height.
* connect to dLWD
* request latest height -> receive 663250
* download and sync blocks from 663150 to 663250
* trigger reorg by calling API (no need to pass params)**
* request latest height -> receive 663251!
* download that block
* observe that the prev hash of that block does not match the hash that we have for 663250
* rewind 10 blocks and request blocks 663241 to 663251
*/
// swiftlint:disable implicitly_unwrapped_optional print_function_usage function_parameter_count
class ReOrgTests: XCTestCase {
// TODO: Parameterize this from environment?
// swiftlint:disable:next line_length
let seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
// TODO: Parameterize this from environment
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a"
let sendAmount: Int64 = 1000
var birthday: BlockHeight = 663150
let defaultLatestHeight: BlockHeight = 663175
let network = DarksideWalletDNetwork()
let branchID = "2bb40e60"
let chainName = "main"
let mockLatestHeight = BlockHeight(663250)
let targetLatestHeight = BlockHeight(663251)
let walletBirthday = BlockHeight(663150)
var birthday: BlockHeight = 663150
var reorgExpectation = XCTestExpectation(description: "reorg")
var coordinator: TestCoordinator!
var syncedExpectation = XCTestExpectation(description: "synced")
var sentTransactionExpectation = XCTestExpectation(description: "sent")
var expectedReorgHeight: BlockHeight = 665188
var expectedRewindHeight: BlockHeight = 665188
let network = DarksideWalletDNetwork()
let branchID = "2bb40e60"
let chainName = "main"
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
override func setUpWithError() throws {
NotificationCenter.default.addObserver(self, selector: #selector(handleReOrgNotification(_:)), name: Notification.Name.blockProcessorHandledReOrg, object: nil)
coordinator = try TestCoordinator(
seed: seedPhrase,
walletBirthday: birthday,
channelProvider: ChannelProvider(),
network: network
)
try super.setUpWithError()
NotificationCenter.default.addObserver(
self,
selector: #selector(handleReOrgNotification(_:)),
name: Notification.Name.blockProcessorHandledReOrg,
object: nil
)
coordinator = try TestCoordinator(
seed: seedPhrase,
walletBirthday: birthday,
channelProvider: ChannelProvider(),
network: network
)
try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
try coordinator.resetBlocks(dataset: .default)
}
override func tearDownWithError() throws {
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
try? FileManager.default.removeItem(at: coordinator.databases.pendingDB)
}
let mockLatestHeight = BlockHeight(663250)
let targetLatestHeight = BlockHeight(663251)
let walletBirthday = BlockHeight(663150)
try coordinator.resetBlocks(dataset: .default)
}
override func tearDownWithError() throws {
try super.tearDownWithError()
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
try? FileManager.default.removeItem(at: coordinator.databases.pendingDB)
}
@objc func handleReOrgNotification(_ notification: Notification) {
reorgExpectation.fulfill()
guard let reorgHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
let rewindHeight = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight else {
@ -81,12 +89,14 @@ class ReOrgTests: XCTestCase {
let reOrgHeight = BlockHeight(663195)
let walletBirthday = WalletBirthday.birthday(with: 663150, network: network).height
try basicReOrgTest(baseDataset: .beforeReOrg,
reorgDataset: .afterSmallReorg,
firstLatestHeight: mockLatestHeight,
reorgHeight: reOrgHeight,
walletBirthday: walletBirthday,
targetHeight: targetLatestHeight)
try basicReOrgTest(
baseDataset: .beforeReOrg,
reorgDataset: .afterSmallReorg,
firstLatestHeight: mockLatestHeight,
reorgHeight: reOrgHeight,
walletBirthday: walletBirthday,
targetHeight: targetLatestHeight
)
}
func testTenPlusBlockReOrg() throws {
@ -95,26 +105,29 @@ class ReOrgTests: XCTestCase {
let reOrgHeight = BlockHeight(663180)
let walletBirthday = WalletBirthday.birthday(with: BlockHeight(663150), network: network).height
try basicReOrgTest(baseDataset: .beforeReOrg,
reorgDataset: .afterLargeReorg,
firstLatestHeight: mockLatestHeight,
reorgHeight: reOrgHeight,
walletBirthday: walletBirthday,
targetHeight: targetLatestHeight)
try basicReOrgTest(
baseDataset: .beforeReOrg,
reorgDataset: .afterLargeReorg,
firstLatestHeight: mockLatestHeight,
reorgHeight: reOrgHeight,
walletBirthday: walletBirthday,
targetHeight: targetLatestHeight
)
}
func basicReOrgTest(baseDataset: DarksideDataset,
reorgDataset: DarksideDataset,
firstLatestHeight: BlockHeight,
reorgHeight: BlockHeight,
walletBirthday: BlockHeight,
targetHeight: BlockHeight) throws {
func basicReOrgTest(
baseDataset: DarksideDataset,
reorgDataset: DarksideDataset,
firstLatestHeight: BlockHeight,
reorgHeight: BlockHeight,
walletBirthday: BlockHeight,
targetHeight: BlockHeight
) throws {
do {
try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
try coordinator.resetBlocks(dataset: .predefined(dataset: .beforeReOrg))
try coordinator.applyStaged(blockheight: firstLatestHeight)
} catch {
} catch {
XCTFail("Error: \(error)")
return
}
@ -122,11 +135,11 @@ class ReOrgTests: XCTestCase {
let firstSyncExpectation = XCTestExpectation(description: "firstSyncExpectation")
/**
download and sync blocks from walletBirthday to firstLatestHeight
*/
download and sync blocks from walletBirthday to firstLatestHeight
*/
var synchronizer: SDKSynchronizer?
try coordinator.sync(completion: { (s) in
synchronizer = s
try coordinator.sync(completion: { synchro in
synchronizer = synchro
firstSyncExpectation.fulfill()
}, error: self.handleError)
@ -136,51 +149,50 @@ class ReOrgTests: XCTestCase {
XCTFail("nil synchronizer")
return
}
/**
verify that mock height has been reached
*/
verify that mock height has been reached
*/
var latestDownloadedHeight = BlockHeight(0)
XCTAssertNoThrow(try {latestDownloadedHeight = try syncedSynchronizer.initializer.downloader.latestBlockHeight()}())
XCTAssertNoThrow(try { latestDownloadedHeight = try syncedSynchronizer.initializer.downloader.latestBlockHeight() }())
XCTAssertTrue(latestDownloadedHeight > 0)
/**
trigger reorg!
*/
trigger reorg!
*/
try coordinator.resetBlocks(dataset: .predefined(dataset: reorgDataset))
try coordinator.applyStaged(blockheight: targetHeight)
/**
request latest height -> receive targetHeight!
download that block
observe that the prev hash of that block does not match the hash that we have for firstLatestHeight
rewind 10 blocks and request blocks targetHeight-10 to targetHeight
*/
request latest height -> receive targetHeight!
download that block
observe that the prev hash of that block does not match the hash that we have for firstLatestHeight
rewind 10 blocks and request blocks targetHeight-10 to targetHeight
*/
let secondSyncExpectation = XCTestExpectation(description: "second sync")
sleep(2)
try coordinator.sync(completion: { (_) in
secondSyncExpectation.fulfill()
}, error: self.handleError)
try coordinator.sync(
completion: { _ in
secondSyncExpectation.fulfill()
},
error: self.handleError
)
// now reorg should happen and reorg notifications and idle notification should be triggered
wait(for: [reorgExpectation,secondSyncExpectation], timeout: 5)
wait(for: [reorgExpectation, secondSyncExpectation], timeout: 5)
// now everything should be fine. latest block should be targetHeight
XCTAssertNoThrow(try {latestDownloadedHeight = try syncedSynchronizer.initializer.downloader.latestBlockHeight()}())
XCTAssertNoThrow(try { latestDownloadedHeight = try syncedSynchronizer.initializer.downloader.latestBlockHeight() }())
XCTAssertEqual(latestDownloadedHeight, targetHeight)
}
@objc func processorHandledReorg(_ notification: Notification) {
XCTAssertNotNil(notification.userInfo)
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
XCTAssertTrue( rewind <= reorg )
reorgExpectation.fulfill()
} else {
@ -195,5 +207,4 @@ class ReOrgTests: XCTestCase {
}
XCTFail("Failed with error: \(testError)")
}
}

View File

@ -7,48 +7,59 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable type_body_length implicitly_unwrapped_optional
class RewindRescanTests: XCTestCase {
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment?
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment
// TODO: Parameterize this from environment?
// swiftlint:disable:next line_length
let seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
// TODO: Parameterize this from environment
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a"
let sendAmount: Int64 = 1000
var birthday: BlockHeight = 663150
let defaultLatestHeight: BlockHeight = 663175
let branchID = "2bb40e60"
let chainName = "main"
var birthday: BlockHeight = 663150
var coordinator: TestCoordinator!
var syncedExpectation = XCTestExpectation(description: "synced")
var sentTransactionExpectation = XCTestExpectation(description: "sent")
var expectedReorgHeight: BlockHeight = 665188
var expectedRewindHeight: BlockHeight = 665188
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
let branchID = "2bb40e60"
let chainName = "main"
var reorgExpectation = XCTestExpectation(description: "reorg")
var network = ZcashNetworkBuilder.network(for: .mainnet)
override func setUpWithError() throws {
try super.setUpWithError()
coordinator = try TestCoordinator(
seed: seedPhrase,
walletBirthday: birthday,
channelProvider: ChannelProvider(),
network: network
)
try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main")
}
override func tearDownWithError() throws {
try super.tearDownWithError()
NotificationCenter.default.removeObserver(self)
try coordinator.stop()
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
try? FileManager.default.removeItem(at: coordinator.databases.pendingDB)
}
func handleError(_ error: Error?) {
guard let testError = error else {
XCTFail("failed with nil error")
return
}
XCTFail("Failed with error: \(testError)")
}
@ -62,7 +73,7 @@ class RewindRescanTests: XCTestCase {
sleep(1)
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
firstSyncExpectation.fulfill()
}, error: handleError)
@ -77,14 +88,14 @@ class RewindRescanTests: XCTestCase {
try coordinator.synchronizer.rewind(.birthday)
// assert that after the new height is
XCTAssertEqual(try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(),self.birthday)
XCTAssertEqual(try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(), self.birthday)
// check that the balance is cleared
XCTAssertEqual(initialVerifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
XCTAssertEqual(initialTotalBalance, coordinator.synchronizer.initializer.getBalance())
let secondScanExpectation = XCTestExpectation(description: "rescan")
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
secondScanExpectation.fulfill()
}, error: handleError)
@ -93,24 +104,28 @@ class RewindRescanTests: XCTestCase {
// verify that the balance still adds up
XCTAssertEqual(verifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance())
}
func testRescanToHeight() throws {
// 1 sync and get spendable funds
try FakeChainBuilder.buildChainWithTxsFarFromEachOther(darksideWallet: coordinator.service, branchID: branchID, chainName: chainName, length: 10000)
try FakeChainBuilder.buildChainWithTxsFarFromEachOther(
darksideWallet: coordinator.service,
branchID: branchID,
chainName: chainName,
length: 10000
)
let newChaintTip = defaultLatestHeight + 10000
try coordinator.applyStaged(blockheight: newChaintTip)
sleep(3)
let initialVerifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
// let initialTotalBalance = coordinator.synchronizer.initializer.getBalance()
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync(completion: { (synchronizer) in
firstSyncExpectation.fulfill()
}, error: handleError)
try coordinator.sync(
completion: { _ in
firstSyncExpectation.fulfill()
},
error: handleError
)
wait(for: [firstSyncExpectation], timeout: 20)
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
@ -121,23 +136,24 @@ class RewindRescanTests: XCTestCase {
// rewind to birthday
let targetHeight: BlockHeight = newChaintTip - 8000
let rewindHeight = ZcashRustBackend.getNearestRewindHeight(dbData: coordinator.databases.dataDB, height: Int32(targetHeight), networkType: network.networkType)
let rewindHeight = ZcashRustBackend.getNearestRewindHeight(
dbData: coordinator.databases.dataDB,
height: Int32(targetHeight),
networkType: network.networkType
)
try coordinator.synchronizer.rewind(.height(blockheight: targetHeight))
guard rewindHeight > 0 else {
XCTFail("get nearest height failed error: \(ZcashRustBackend.getLastError() ?? "null")")
return
}
// assert that after the new height is
// XCTAssertEqual(try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(), BlockHeight(rewindHeight))
// check that the balance is cleared
XCTAssertEqual(initialVerifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
let secondScanExpectation = XCTestExpectation(description: "rescan")
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
secondScanExpectation.fulfill()
}, error: handleError)
@ -149,7 +165,13 @@ class RewindRescanTests: XCTestCase {
// try to spend the funds
let sendExpectation = XCTestExpectation(description: "after rewind expectation")
coordinator.synchronizer.sendToAddress(spendingKey: coordinator.spendingKey, zatoshi: 1000, toAddress: testRecipientAddress, memo: nil, from: 0) { result in
coordinator.synchronizer.sendToAddress(
spendingKey: coordinator.spendingKey,
zatoshi: 1000,
toAddress: testRecipientAddress,
memo: nil,
from: 0
) { result in
sendExpectation.fulfill()
switch result {
case .success(let pendingTx):
@ -159,9 +181,6 @@ class RewindRescanTests: XCTestCase {
}
}
wait(for: [sendExpectation], timeout: 15)
}
func testRescanToTransaction() throws {
@ -173,7 +192,7 @@ class RewindRescanTests: XCTestCase {
sleep(1)
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
firstSyncExpectation.fulfill()
}, error: handleError)
@ -191,14 +210,16 @@ class RewindRescanTests: XCTestCase {
}
try coordinator.synchronizer.rewind(.transaction(transaction.transactionEntity))
// assert that after the new height is
XCTAssertEqual(try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(),transaction.transactionEntity.anchor(network: network))
XCTAssertEqual(
try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(),
transaction.transactionEntity.anchor(network: network)
)
let secondScanExpectation = XCTestExpectation(description: "rescan")
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
secondScanExpectation.fulfill()
}, error: handleError)
@ -207,7 +228,6 @@ class RewindRescanTests: XCTestCase {
// verify that the balance still adds up
XCTAssertEqual(verifiedBalance, coordinator.synchronizer.initializer.getVerifiedBalance())
XCTAssertEqual(totalBalance, coordinator.synchronizer.initializer.getBalance())
}
func testRewindAfterSendingTransaction() throws {
@ -225,7 +245,7 @@ class RewindRescanTests: XCTestCase {
sleep(1)
let firstSyncExpectation = XCTestExpectation(description: "first sync expectation")
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
firstSyncExpectation.fulfill()
}, error: handleError)
@ -246,11 +266,13 @@ class RewindRescanTests: XCTestCase {
return
}
var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
zatoshi: maxBalance,
toAddress: testRecipientAddress,
memo: "test send \(self.description) \(Date().description)",
from: 0) { result in
coordinator.synchronizer.sendToAddress(
spendingKey: spendingKey,
zatoshi: maxBalance,
toAddress: testRecipientAddress,
memo: "test send \(self.description) \(Date().description)",
from: 0
) { result in
switch result {
case .failure(let error):
XCTFail("sendToAddress failed: \(error)")
@ -265,14 +287,13 @@ class RewindRescanTests: XCTestCase {
return
}
notificationHandler.synchronizerMinedTransaction = { tx in
XCTAssertNotNil(tx.rawTransactionId)
notificationHandler.synchronizerMinedTransaction = { transaction in
XCTAssertNotNil(transaction.rawTransactionId)
XCTAssertNotNil(pendingTx.rawTransactionId)
XCTAssertEqual(tx.rawTransactionId, pendingTx.rawTransactionId)
XCTAssertEqual(transaction.rawTransactionId, pendingTx.rawTransactionId)
transactionMinedExpectation.fulfill()
}
// 5 apply to height
// 6 mine the block
guard let rawTx = try coordinator.getIncomingTransactions()?.first else {
@ -284,7 +305,7 @@ class RewindRescanTests: XCTestCase {
let sentTxHeight = latestHeight + 1
notificationHandler.transactionsFound = { txs in
let foundTx = txs.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId})
let foundTx = txs.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
XCTAssertNotNil(foundTx)
XCTAssertEqual(foundTx?.minedHeight, sentTxHeight)
@ -296,24 +317,26 @@ class RewindRescanTests: XCTestCase {
try coordinator.applyStaged(blockheight: sentTxHeight)
sleep(2)
let mineExpectation = XCTestExpectation(description: "mineTxExpectation")
try coordinator.sync(completion: { (synchronizer) in
let p = synchronizer.pendingTransactions.first(where: {$0.rawTransactionId == pendingTx.rawTransactionId})
XCTAssertNotNil(p, "pending transaction should have been mined by now")
XCTAssertTrue(p?.isMined ?? false)
XCTAssertEqual(p?.minedHeight, sentTxHeight)
mineExpectation.fulfill()
try coordinator.sync(
completion: { synchronizer in
let pendingTransaction = synchronizer.pendingTransactions
.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
XCTAssertNotNil(pendingTransaction, "pending transaction should have been mined by now")
XCTAssertTrue(pendingTransaction?.isMined ?? false)
XCTAssertEqual(pendingTransaction?.minedHeight, sentTxHeight)
mineExpectation.fulfill()
},
error: { error in
guard let e = error else {
XCTFail("unknown error syncing after sending transaction")
return
}
}, error: { (error) in
guard let e = error else {
XCTFail("unknown error syncing after sending transaction")
return
XCTFail("Error: \(e)")
}
XCTFail("Error: \(e)")
})
)
wait(for: [mineExpectation, transactionMinedExpectation, foundTransactionsExpectation], timeout: 5)
@ -327,36 +350,45 @@ class RewindRescanTests: XCTestCase {
try coordinator.synchronizer.rewind(.height(blockheight: sentTxHeight - 5))
guard let np = try coordinator.synchronizer.allPendingTransactions().first(where: { $0.rawTransactionId == pendingTx.rawTransactionId}) else {
guard
let pendingEntity = try coordinator.synchronizer.allPendingTransactions()
.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
else {
XCTFail("sent pending transaction not found after rewind")
return
}
XCTAssertFalse(np.isMined)
XCTAssertFalse(pendingEntity.isMined)
let confirmExpectation = XCTestExpectation(description: "confirm expectation")
notificationHandler.transactionsFound = { txs in
XCTAssertEqual(txs.count, 1)
guard let t = txs.first else {
guard let transaction = txs.first else {
XCTFail("should have found sent transaction but didn't")
return
}
XCTAssertEqual(t.rawTransactionId, pendingTx.rawTransactionId,"should have mined sent transaction but didn't")
XCTAssertEqual(transaction.rawTransactionId, pendingTx.rawTransactionId, "should have mined sent transaction but didn't")
}
notificationHandler.synchronizerMinedTransaction = { tx in
XCTFail("We shouldn't find any mined transactions at this point but found \(tx)")
notificationHandler.synchronizerMinedTransaction = { transaction in
XCTFail("We shouldn't find any mined transactions at this point but found \(transaction)")
}
try coordinator.sync(completion: { synchronizer in
confirmExpectation.fulfill()
}, error: { e in
self.handleError(e)
})
try coordinator.sync(
completion: { _ in
confirmExpectation.fulfill()
},
error: { e in
self.handleError(e)
}
)
wait(for: [confirmExpectation], timeout: 10)
let confirmedPending = try coordinator.synchronizer.allPendingTransactions().first(where: { $0.rawTransactionId == pendingTx.rawTransactionId})
let confirmedPending = try coordinator.synchronizer.allPendingTransactions()
.first(where: { $0.rawTransactionId == pendingTx.rawTransactionId })
XCTAssertNil(confirmedPending, "pending, now confirmed transaction found")
XCTAssertEqual(coordinator.synchronizer.initializer.getBalance(), 0)
XCTAssertEqual(coordinator.synchronizer.initializer.getVerifiedBalance(), 0)
}

View File

@ -7,26 +7,32 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable implicitly_unwrapped_optional
class SychronizerDarksideTests: XCTestCase {
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment?
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment
// TODO: Parameterize this from environment?
// swiftlint:disable:next line_length
let seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
// TODO: Parameterize this from environment
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a"
let sendAmount: Int64 = 1000
var birthday: BlockHeight = 663150
let defaultLatestHeight: BlockHeight = 663175
let branchID = "2bb40e60"
let chainName = "main"
let network = DarksideWalletDNetwork()
var birthday: BlockHeight = 663150
var coordinator: TestCoordinator!
var syncedExpectation = XCTestExpectation(description: "synced")
var sentTransactionExpectation = XCTestExpectation(description: "sent")
var expectedReorgHeight: BlockHeight = 665188
var expectedRewindHeight: BlockHeight = 665188
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
let branchID = "2bb40e60"
let chainName = "main"
let network = DarksideWalletDNetwork()
var foundTransactions = [ConfirmedTransactionEntity]()
var reorgExpectation = XCTestExpectation(description: "reorg")
var foundTransactions: [ConfirmedTransactionEntity] = []
override func setUpWithError() throws {
try super.setUpWithError()
coordinator = try TestCoordinator(
seed: seedPhrase,
walletBirthday: birthday,
@ -37,6 +43,7 @@ class SychronizerDarksideTests: XCTestCase {
}
override func tearDownWithError() throws {
try super.tearDownWithError()
NotificationCenter.default.removeObserver(self)
try coordinator.stop()
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
@ -45,20 +52,22 @@ class SychronizerDarksideTests: XCTestCase {
}
func testFoundTransactions() throws {
NotificationCenter.default.addObserver(self, selector: #selector(handleFoundTransactions(_:)), name: Notification.Name.synchronizerFoundTransactions, object: nil)
NotificationCenter.default.addObserver(
self,
selector: #selector(handleFoundTransactions(_:)),
name: Notification.Name.synchronizerFoundTransactions,
object: nil
)
try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName)
let receivedTxHeight: BlockHeight = 663188
try coordinator.applyStaged(blockheight: receivedTxHeight + 1)
sleep(2)
let preTxExpectation = XCTestExpectation(description: "pre receive")
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
preTxExpectation.fulfill()
}, error: self.handleError)
@ -68,20 +77,22 @@ class SychronizerDarksideTests: XCTestCase {
}
func testFoundManyTransactions() throws {
NotificationCenter.default.addObserver(self, selector: #selector(handleFoundTransactions(_:)), name: Notification.Name.synchronizerFoundTransactions, object: nil)
NotificationCenter.default.addObserver(
self,
selector: #selector(handleFoundTransactions(_:)),
name: Notification.Name.synchronizerFoundTransactions,
object: nil
)
try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName,length: 1000)
try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName, length: 1000)
let receivedTxHeight: BlockHeight = 663229
try coordinator.applyStaged(blockheight: receivedTxHeight + 1)
sleep(2)
let firsTxExpectation = XCTestExpectation(description: "first sync")
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
firsTxExpectation.fulfill()
}, error: self.handleError)
@ -95,36 +106,34 @@ class SychronizerDarksideTests: XCTestCase {
sleep(2)
let preTxExpectation = XCTestExpectation(description: "intermediate sync")
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
preTxExpectation.fulfill()
}, error: self.handleError)
wait(for: [preTxExpectation], timeout: 10)
XCTAssertTrue(self.foundTransactions.count == 0)
XCTAssertTrue(self.foundTransactions.isEmpty)
let findManyTxExpectation = XCTestExpectation(description: "final sync")
try coordinator.applyStaged(blockheight: 664010)
sleep(2)
try coordinator.sync(completion: { (synchronizer) in
try coordinator.sync(completion: { _ in
findManyTxExpectation.fulfill()
}, error: self.handleError)
wait(for: [findManyTxExpectation], timeout: 10)
XCTAssertEqual(self.foundTransactions.count, 2)
}
@objc func handleFoundTransactions(_ notification: Notification) {
guard let userInfo = notification.userInfo,
let transactions = userInfo[SDKSynchronizer.NotificationKeys.foundTransactions] as? [ConfirmedTransactionEntity] else {
guard
let userInfo = notification.userInfo,
let transactions = userInfo[SDKSynchronizer.NotificationKeys.foundTransactions] as? [ConfirmedTransactionEntity]
else {
return
}
self.foundTransactions.append(contentsOf: transactions)

View File

@ -9,13 +9,13 @@ import Foundation
@testable import ZcashLightClientKit
/**
This is the TestCoordinator
What does it do? quite a lot.
Is it a nice "SOLID" "Clean Code" piece of source code?
Hell no. It's your testing overlord and you will be grateful it is.
*/
This is the TestCoordinator
What does it do? quite a lot.
Is it a nice "SOLID" "Clean Code" piece of source code?
Hell no. It's your testing overlord and you will be grateful it is.
*/
// swiftlint:disable force_try function_parameter_count
class TestCoordinator {
enum CoordinatorError: Error {
case notDarksideWallet
case notificationFromUnknownSynchronizer
@ -44,22 +44,43 @@ class TestCoordinator {
var spendingKeys: [String]?
var databases: TemporaryTestDatabases
let network: ZcashNetwork
convenience init(seed: String,
walletBirthday: BlockHeight,
channelProvider: ChannelProvider,
network: ZcashNetwork) throws {
convenience init(
seed: String,
walletBirthday: BlockHeight,
channelProvider: ChannelProvider,
network: ZcashNetwork
) throws {
let derivationTool = DerivationTool(networkType: network.networkType)
guard let spendingKey = try derivationTool.deriveSpendingKeys(
seed: TestSeed().seed(),
numberOfAccounts: 1).first else {
guard
let spendingKey = try derivationTool
.deriveSpendingKeys(
seed: TestSeed().seed(),
numberOfAccounts: 1
)
.first
else {
throw CoordinatorError.builderError
}
guard let uvk = try derivationTool.deriveUnifiedViewingKeysFromSeed(TestSeed().seed(), numberOfAccounts: 1).first else {
guard
let uvk = try derivationTool
.deriveUnifiedViewingKeysFromSeed(
TestSeed().seed(),
numberOfAccounts: 1
)
.first
else {
throw CoordinatorError.builderError
}
try self.init(spendingKey: spendingKey, unifiedViewingKey: uvk, walletBirthday: walletBirthday, channelProvider: channelProvider, network: network)
try self.init(
spendingKey: spendingKey,
unifiedViewingKey: uvk,
walletBirthday: walletBirthday,
channelProvider: channelProvider,
network: network
)
}
required init(
@ -67,35 +88,47 @@ class TestCoordinator {
unifiedViewingKey: UnifiedViewingKey,
walletBirthday: BlockHeight,
channelProvider: ChannelProvider,
network: ZcashNetwork) throws {
network: ZcashNetwork
) throws {
self.spendingKey = spendingKey
self.birthday = walletBirthday
self.channelProvider = channelProvider
self.databases = TemporaryDbBuilder.build()
self.network = network
self.service = DarksideWalletService(service: LightWalletGRPCService(host: Constants.address, port: 9067, secure: false, singleCallTimeout: 10000, streamingCallTimeout: 1000000))
self.service = DarksideWalletService(
service: LightWalletGRPCService(
host: Constants.address,
port: 9067,
secure: false,
singleCallTimeout: 10000,
streamingCallTimeout: 1000000
)
)
let storage = CompactBlockStorage(url: databases.cacheDB, readonly: false)
try storage.createTable()
let buildResult = try TestSynchronizerBuilder.build(
rustBackend: ZcashRustBackend.self,
lowerBoundHeight: self.birthday,
cacheDbURL: databases.cacheDB,
dataDbURL: databases.dataDB,
pendingDbURL: databases.pendingDB,
endpoint: LightWalletEndpointBuilder.default,
service: self.service,
repository: TransactionSQLDAO(dbProvider: SimpleConnectionProvider(path: databases.dataDB.absoluteString)),
accountRepository: AccountRepositoryBuilder.build(dataDbURL: databases.dataDB,
readOnly: true),
storage: storage,
spendParamsURL: try __spendParamsURL(),
outputParamsURL: try __outputParamsURL(),
spendingKey: spendingKey,
unifiedViewingKey: unifiedViewingKey,
walletBirthday: WalletBirthday.birthday(with: birthday, network: network),
network: network,
loggerProxy: SampleLogger(logLevel: .debug))
rustBackend: ZcashRustBackend.self,
lowerBoundHeight: self.birthday,
cacheDbURL: databases.cacheDB,
dataDbURL: databases.dataDB,
pendingDbURL: databases.pendingDB,
endpoint: LightWalletEndpointBuilder.default,
service: self.service,
repository: TransactionSQLDAO(dbProvider: SimpleConnectionProvider(path: databases.dataDB.absoluteString)),
accountRepository: AccountRepositoryBuilder.build(
dataDbURL: databases.dataDB,
readOnly: true
),
storage: storage,
spendParamsURL: try __spendParamsURL(),
outputParamsURL: try __outputParamsURL(),
spendingKey: spendingKey,
unifiedViewingKey: unifiedViewingKey,
walletBirthday: WalletBirthday.birthday(with: birthday, network: network),
network: network,
loggerProxy: SampleLogger(logLevel: .debug)
)
self.synchronizer = buildResult.synchronizer
self.spendingKeys = buildResult.spendingKeys
@ -114,7 +147,7 @@ class TestCoordinator {
try service.useDataset(DarksideDataset.beforeReOrg.rawValue)
case .predefined(let dataset):
try service.useDataset(dataset.rawValue)
case .url(let urlString,_):
case .url(let urlString, _):
try service.useDataset(from: urlString)
}
}
@ -130,15 +163,12 @@ class TestCoordinator {
try synchronizer.start(retry: true)
}
/**
Notifications
*/
Notifications
*/
func subscribeToNotifications(synchronizer: Synchronizer) {
NotificationCenter.default.addObserver(self, selector: #selector(synchronizerFailed(_:)), name: .synchronizerFailed, object: synchronizer)
NotificationCenter.default.addObserver(self, selector: #selector(synchronizerSynced(_:)), name: .synchronizerSynced, object: synchronizer)
}
@objc func synchronizerFailed(_ notification: Notification) {
@ -172,13 +202,12 @@ class TestCoordinator {
extension TestCoordinator {
func resetBlocks(dataset: DarksideData) throws {
switch dataset {
case .default:
try service.useDataset(DarksideDataset.beforeReOrg.rawValue)
case .predefined(let blocks):
try service.useDataset(blocks.rawValue)
case .url(let urlString,_):
case .url(let urlString, _):
try service.useDataset(urlString)
}
}
@ -191,8 +220,8 @@ extension TestCoordinator {
try service.applyStaged(nextLatestHeight: blockheight)
}
func stageTransaction(_ tx: RawTransaction, at height: BlockHeight) throws {
try service.stageTransaction(tx, at: height)
func stageTransaction(_ transaction: RawTransaction, at height: BlockHeight) throws {
try service.stageTransaction(transaction, at: height)
}
func stageTransaction(url: String, at height: BlockHeight) throws {
@ -206,17 +235,17 @@ extension TestCoordinator {
func reset(saplingActivation: BlockHeight, branchID: String, chainName: String) throws {
let config = self.synchronizer.blockProcessor.config
self.synchronizer.blockProcessor.config = CompactBlockProcessor.Configuration(
cacheDb: config.cacheDb,
dataDb: config.dataDb,
downloadBatchSize: config.downloadBatchSize,
retries: config.retries,
maxBackoffInterval: config.maxBackoffInterval,
rewindDistance: config.rewindDistance,
walletBirthday: config.walletBirthday,
saplingActivation: config.saplingActivation,
network: config.network)
cacheDb: config.cacheDb,
dataDb: config.dataDb,
downloadBatchSize: config.downloadBatchSize,
retries: config.retries,
maxBackoffInterval: config.maxBackoffInterval,
rewindDistance: config.rewindDistance,
walletBirthday: config.walletBirthday,
saplingActivation: config.saplingActivation,
network: config.network
)
try service.reset(saplingActivation: saplingActivation, branchID: branchID, chainName: chainName)
}
@ -226,24 +255,25 @@ extension TestCoordinator {
}
struct TemporaryTestDatabases {
var cacheDB: URL
var dataDB: URL
var pendingDB: URL
var cacheDB: URL
var dataDB: URL
var pendingDB: URL
}
class TemporaryDbBuilder {
enum TemporaryDbBuilder {
static func build() -> TemporaryTestDatabases {
let tempUrl = try! __documentsDirectory()
let timestamp = String(Int(Date().timeIntervalSince1970))
return TemporaryTestDatabases(cacheDB: tempUrl.appendingPathComponent("cache_db_\(timestamp).db"),
dataDB: tempUrl.appendingPathComponent("data_db_\(timestamp).db"),
pendingDB: tempUrl.appendingPathComponent("pending_db_\(timestamp).db"))
return TemporaryTestDatabases(
cacheDB: tempUrl.appendingPathComponent("cache_db_\(timestamp).db"),
dataDB: tempUrl.appendingPathComponent("data_db_\(timestamp).db"),
pendingDB: tempUrl.appendingPathComponent("pending_db_\(timestamp).db")
)
}
}
class TestSynchronizerBuilder {
enum TestSynchronizerBuilder {
static func build(
rustBackend: ZcashRustBackendWelding.Type,
lowerBoundHeight: BlockHeight,
@ -262,7 +292,7 @@ class TestSynchronizerBuilder {
walletBirthday: WalletBirthday,
network: ZcashNetwork,
loggerProxy: Logger? = nil
) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) {
) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) {
let initializer = Initializer(
rustBackend: rustBackend,
lowerBoundHeight: lowerBoundHeight,
@ -281,37 +311,42 @@ class TestSynchronizerBuilder {
walletBirthday: walletBirthday.height,
loggerProxy: loggerProxy
)
let config = CompactBlockProcessor.Configuration(
cacheDb: initializer.cacheDbURL,
dataDb: initializer.dataDbURL,
downloadBatchSize: 100,
retries: 5,
maxBackoffInterval: ZcashSDK.defaultMaxBackOffInterval,
rewindDistance: ZcashSDK.defaultRewindDistance,
walletBirthday: walletBirthday.height,
saplingActivation: lowerBoundHeight,
network: network)
cacheDb: initializer.cacheDbURL,
dataDb: initializer.dataDbURL,
downloadBatchSize: 100,
retries: 5,
maxBackoffInterval: ZcashSDK.defaultMaxBackOffInterval,
rewindDistance: ZcashSDK.defaultRewindDistance,
walletBirthday: walletBirthday.height,
saplingActivation: lowerBoundHeight,
network: network
)
let processor = CompactBlockProcessor(service: service,
storage: storage,
backend: rustBackend,
config: config,
repository: repository,
accountRepository: accountRepository)
let processor = CompactBlockProcessor(
service: service,
storage: storage,
backend: rustBackend,
config: config,
repository: repository,
accountRepository: accountRepository
)
let synchronizer = try SDKSynchronizer(status: .unprepared,
initializer: initializer,
transactionManager: OutboundTransactionManagerBuilder.build(initializer: initializer),
transactionRepository: repository,
utxoRepository: UTXORepositoryBuilder.build(initializer: initializer),
blockProcessor: processor
)
let synchronizer = try SDKSynchronizer(
status: .unprepared,
initializer: initializer,
transactionManager: OutboundTransactionManagerBuilder.build(initializer: initializer),
transactionRepository: repository,
utxoRepository: UTXORepositoryBuilder.build(initializer: initializer),
blockProcessor: processor
)
try synchronizer.prepare()
return ([spendingKey], synchronizer)
}
static func build(
rustBackend: ZcashRustBackendWelding.Type,
lowerBoundHeight: BlockHeight,
@ -330,14 +365,23 @@ class TestSynchronizerBuilder {
network: ZcashNetwork,
loggerProxy: Logger? = nil
) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) {
guard let spendingKey = try DerivationTool(networkType: network.networkType).deriveSpendingKeys(seed: seedBytes, numberOfAccounts: 1).first else {
guard
let spendingKey = try DerivationTool(networkType: network.networkType)
.deriveSpendingKeys(seed: seedBytes, numberOfAccounts: 1)
.first
else {
throw TestCoordinator.CoordinatorError.builderError
}
guard let uvk = try DerivationTool(networkType: network.networkType).deriveUnifiedViewingKeysFromSeed(seedBytes, numberOfAccounts: 1).first else {
guard let uvk = try DerivationTool(networkType: network.networkType)
.deriveUnifiedViewingKeysFromSeed(seedBytes, numberOfAccounts: 1)
.first
else {
throw TestCoordinator.CoordinatorError.builderError
}
return try build(rustBackend: rustBackend,
return try build(
rustBackend: rustBackend,
lowerBoundHeight: lowerBoundHeight,
cacheDbURL: cacheDbURL,
dataDbURL: dataDbURL,
@ -352,8 +396,7 @@ class TestSynchronizerBuilder {
spendingKey: spendingKey,
unifiedViewingKey: uvk,
walletBirthday: walletBirthday,
network: network)
network: network
)
}
}

View File

@ -7,7 +7,16 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable implicitly_unwrapped_optional force_try
class TransactionEnhancementTests: XCTestCase {
let mockLatestHeight = BlockHeight(663250)
let targetLatestHeight = BlockHeight(663251)
let walletBirthday = BlockHeight(663150)
let network = DarksideWalletDNetwork()
let branchID = "2bb40e60"
let chainName = "main"
var initializer: Initializer!
var processorConfig: CompactBlockProcessor.Configuration!
var processor: CompactBlockProcessor!
@ -23,26 +32,26 @@ class TransactionEnhancementTests: XCTestCase {
var afterReorgIdleNotification: XCTestExpectation!
var txFoundNotificationExpectation: XCTestExpectation!
var waitExpectation: XCTestExpectation!
let mockLatestHeight = BlockHeight(663250)
let targetLatestHeight = BlockHeight(663251)
let walletBirthday = BlockHeight(663150)
let network = DarksideWalletDNetwork()
let branchID = "2bb40e60"
let chainName = "main"
override func setUpWithError() throws {
try super.setUpWithError()
logger = SampleLogger(logLevel: .debug)
downloadStartedExpect = XCTestExpectation(description: self.description + " downloadStartedExpect")
stopNotificationExpectation = XCTestExpectation(description: self.description + " stopNotificationExpectation")
updatedNotificationExpectation = XCTestExpectation(description: self.description + " updatedNotificationExpectation")
startedValidatingNotificationExpectation = XCTestExpectation(description: self.description + " startedValidatingNotificationExpectation")
startedScanningNotificationExpectation = XCTestExpectation(description: self.description + " startedScanningNotificationExpectation")
idleNotificationExpectation = XCTestExpectation(description: self.description + " idleNotificationExpectation")
afterReorgIdleNotification = XCTestExpectation(description: self.description + " afterReorgIdleNotification")
reorgNotificationExpectation = XCTestExpectation(description: self.description + " reorgNotificationExpectation")
txFoundNotificationExpectation = XCTestExpectation(description: self.description + "txFoundNotificationExpectation")
downloadStartedExpect = XCTestExpectation(description: "\(self.description) downloadStartedExpect")
stopNotificationExpectation = XCTestExpectation(description: "\(self.description) stopNotificationExpectation")
updatedNotificationExpectation = XCTestExpectation(description: "\(self.description) updatedNotificationExpectation")
startedValidatingNotificationExpectation = XCTestExpectation(
description: "\(self.description) startedValidatingNotificationExpectation"
)
startedScanningNotificationExpectation = XCTestExpectation(
description: "\(self.description) startedScanningNotificationExpectation"
)
idleNotificationExpectation = XCTestExpectation(description: "\(self.description) idleNotificationExpectation")
afterReorgIdleNotification = XCTestExpectation(description: "\(self.description) afterReorgIdleNotification")
reorgNotificationExpectation = XCTestExpectation(description: "\(self.description) reorgNotificationExpectation")
txFoundNotificationExpectation = XCTestExpectation(description: "\(self.description) txFoundNotificationExpectation")
waitExpectation = XCTestExpectation(description: self.description + "waitExpectation")
waitExpectation = XCTestExpectation(description: "\(self.description) waitExpectation")
let birthday = WalletBirthday.birthday(with: walletBirthday, network: network)
@ -50,14 +59,19 @@ class TransactionEnhancementTests: XCTestCase {
let rustBackend = ZcashRustBackend.self
processorConfig = config
try? FileManager.default.removeItem(at: processorConfig.cacheDb)
try? FileManager.default.removeItem(at: processorConfig.dataDb)
_ = rustBackend.initAccountsTable(dbData: processorConfig.dataDb, seed: TestSeed().seed(), accounts: 1,networkType: network.networkType)
_ = rustBackend.initAccountsTable(dbData: processorConfig.dataDb, seed: TestSeed().seed(), accounts: 1, networkType: network.networkType)
_ = try rustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: network.networkType)
_ = try rustBackend.initBlocksTable(dbData: processorConfig.dataDb, height: Int32(birthday.height), hash: birthday.hash, time: birthday.time, saplingTree: birthday.tree, networkType: network.networkType)
_ = try rustBackend.initBlocksTable(
dbData: processorConfig.dataDb,
height: Int32(birthday.height),
hash: birthday.hash,
time: birthday.time,
saplingTree: birthday.tree,
networkType: network.networkType
)
let service = DarksideWalletService()
darksideWalletService = service
@ -65,17 +79,23 @@ class TransactionEnhancementTests: XCTestCase {
try! storage.createTable()
downloader = CompactBlockDownloader(service: service, storage: storage)
processor = CompactBlockProcessor(service: service,
storage: storage,
backend: rustBackend,
config: processorConfig)
processor = CompactBlockProcessor(
service: service,
storage: storage,
backend: rustBackend,
config: processorConfig
)
NotificationCenter.default.addObserver(self, selector: #selector(processorFailed(_:)), name: Notification.Name.blockProcessorFailed, object: processor)
NotificationCenter.default.addObserver(
self,
selector: #selector(processorFailed(_:)),
name: Notification.Name.blockProcessorFailed,
object: processor
)
}
override func tearDownWithError() throws {
try super.tearDownWithError()
try? FileManager.default.removeItem(at: processorConfig.cacheDb)
try? FileManager.default.removeItem(at: processorConfig.dataDb)
downloadStartedExpect.unsubscribeFromNotifications()
@ -89,7 +109,7 @@ class TransactionEnhancementTests: XCTestCase {
NotificationCenter.default.removeObserver(self)
}
fileprivate func startProcessing() throws {
private func startProcessing() throws {
XCTAssertNotNil(processor)
// Subscribe to notifications
@ -98,13 +118,11 @@ class TransactionEnhancementTests: XCTestCase {
updatedNotificationExpectation.subscribe(to: Notification.Name.blockProcessorUpdated, object: processor)
startedValidatingNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedValidating, object: processor)
startedScanningNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedScanning, object: processor)
try processor.start()
}
func testBasicEnhacement() throws {
let targetLatestHeight = BlockHeight(663250)
let walletBirthday = WalletBirthday.birthday(with: 663151, network: network).height
@ -112,47 +130,48 @@ class TransactionEnhancementTests: XCTestCase {
}
func basicEnhancementTest(latestHeight: BlockHeight, walletBirthday: BlockHeight) throws {
do {
try darksideWalletService.reset(saplingActivation: 663150, branchID: branchID, chainName: chainName)
try darksideWalletService.useDataset(DarksideDataset.beforeReOrg.rawValue)
try darksideWalletService.applyStaged(nextLatestHeight: 663200)
} catch {
} catch {
XCTFail("Error: \(error)")
return
}
sleep(3)
/**
connect to dLWD
request latest height -> receive firstLatestHeight
*/
connect to dLWD
request latest height -> receive firstLatestHeight
*/
do {
print("first latest height: \(try darksideWalletService.latestBlockHeight())")
dump("first latest height: \(try darksideWalletService.latestBlockHeight())")
} catch {
XCTFail("Error: \(error)")
return
}
/**
download and sync blocks from walletBirthday to firstLatestHeight
*/
download and sync blocks from walletBirthday to firstLatestHeight
*/
do {
try startProcessing()
} catch {
XCTFail("Error: \(error)")
}
wait(for: [downloadStartedExpect,
startedValidatingNotificationExpectation,
startedScanningNotificationExpectation,
txFoundNotificationExpectation,
idleNotificationExpectation], timeout: 30)
idleNotificationExpectation.unsubscribeFromNotifications()
wait(
for: [
downloadStartedExpect,
startedValidatingNotificationExpectation,
startedScanningNotificationExpectation,
txFoundNotificationExpectation,
idleNotificationExpectation
],
timeout: 30
)
idleNotificationExpectation.unsubscribeFromNotifications()
}
@objc func processorFailed(_ notification: Notification) {
@ -163,6 +182,4 @@ class TransactionEnhancementTests: XCTestCase {
XCTFail("CompactBlockProcessor failed")
}
}
}

View File

@ -7,37 +7,39 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable implicitly_unwrapped_optional force_unwrapping
class TransactionRepositoryTests: XCTestCase {
var transactionRepository: TransactionRepository!
override func setUp() {
super.setUp()
transactionRepository = TestDbBuilder.transactionRepository()
}
override func tearDown() {
super.tearDown()
transactionRepository = nil
}
func testCount() {
var count: Int?
XCTAssertNoThrow(try { count = try self.transactionRepository.countAll()}())
XCTAssertNoThrow(try { count = try self.transactionRepository.countAll() }())
XCTAssertNotNil(count)
XCTAssertEqual(count, 27)
}
func testCountUnmined() {
var count: Int?
XCTAssertNoThrow(try { count = try self.transactionRepository.countUnmined()}())
XCTAssertNoThrow(try { count = try self.transactionRepository.countUnmined() }())
XCTAssertNotNil(count)
XCTAssertEqual(count, 0)
}
func testFindById() {
var tx: TransactionEntity?
XCTAssertNoThrow(try { tx = try self.transactionRepository.findBy(id: 10)}())
guard let transaction = tx else {
var transaction: TransactionEntity?
XCTAssertNoThrow(try { transaction = try self.transactionRepository.findBy(id: 10) }())
guard let transaction = transaction else {
XCTFail("transaction is nil")
return
}
@ -45,16 +47,18 @@ class TransactionRepositoryTests: XCTestCase {
XCTAssertEqual(transaction.id, 10)
XCTAssertEqual(transaction.minedHeight, 652812)
XCTAssertEqual(transaction.transactionIndex, 5)
}
func testFindByTxId() {
var tx: TransactionEntity?
var transaction: TransactionEntity?
let id = Data(fromHexEncodedString: "0BAFC5B83F5B39A5270144ECD98DBC65115055927EDDA8FF20F081FFF13E4780")!
XCTAssertNoThrow(try { tx = try self.transactionRepository.findBy(rawId: id)}())
guard let transaction = tx else {
XCTAssertNoThrow(
try { transaction = try self.transactionRepository.findBy(rawId: id) }()
)
guard let transaction = transaction else {
XCTFail("transaction is nil")
return
}
@ -111,16 +115,17 @@ class TransactionRepositoryTests: XCTestCase {
}
func testFindAllFrom() throws {
guard let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max),
let allFromNil = try self.transactionRepository.findAll(from: nil, limit: Int.max)
guard
let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max),
let allFromNil = try self.transactionRepository.findAll(from: nil, limit: Int.max)
else {
return XCTFail("find all failed")
}
XCTAssertEqual(transactions.count, allFromNil.count)
for t in transactions {
guard allFromNil.first(where: { $0.rawTransactionId == t.rawTransactionId}) != nil else {
for transaction in transactions {
guard allFromNil.first(where: { $0.rawTransactionId == transaction.rawTransactionId }) != nil else {
XCTFail("not equal")
return
}
@ -128,11 +133,11 @@ class TransactionRepositoryTests: XCTestCase {
}
func testFindAllFromSlice() throws {
let limit = 4
let start = 7
guard let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max),
let allFromNil = try self.transactionRepository.findAll(from: transactions[start], limit: limit)
guard
let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max),
let allFromNil = try self.transactionRepository.findAll(from: transactions[start], limit: limit)
else {
return XCTFail("find all failed")
}
@ -141,29 +146,28 @@ class TransactionRepositoryTests: XCTestCase {
let slice = transactions[start + 1 ... start + limit]
XCTAssertEqual(slice.count, allFromNil.count)
for t in slice {
guard allFromNil.first(where: { $0.rawTransactionId == t.rawTransactionId}) != nil else {
for transaction in slice {
guard allFromNil.first(where: { $0.rawTransactionId == transaction.rawTransactionId }) != nil else {
XCTFail("not equal")
return
}
}
}
func testFindAllFromLastSlice() throws {
let limit = 10
let start = 20
guard let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max),
let allFromNil = try self.transactionRepository.findAll(from: transactions[start], limit: limit)
guard
let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max),
let allFromNil = try self.transactionRepository.findAll(from: transactions[start], limit: limit)
else {
return XCTFail("find all failed")
}
let slice = transactions[start + 1 ..< transactions.count]
XCTAssertEqual(slice.count, allFromNil.count)
for t in slice {
guard allFromNil.first(where: { $0.rawTransactionId == t.rawTransactionId}) != nil else {
for transaction in slice {
guard allFromNil.first(where: { $0.rawTransactionId == transaction.rawTransactionId }) != nil else {
XCTFail("not equal")
return
}
@ -172,36 +176,34 @@ class TransactionRepositoryTests: XCTestCase {
}
extension Data {
init?(fromHexEncodedString string: String) {
// Convert 0 ... 9, a ... f, A ...F to their decimal value,
// return nil for all other input characters
func decodeNibble(u: UInt16) -> UInt8? {
switch(u) {
func decodeNibble(bytes: UInt16) -> UInt8? {
switch bytes {
case 0x30 ... 0x39:
return UInt8(u - 0x30)
return UInt8(bytes - 0x30)
case 0x41 ... 0x46:
return UInt8(u - 0x41 + 10)
return UInt8(bytes - 0x41 + 10)
case 0x61 ... 0x66:
return UInt8(u - 0x61 + 10)
return UInt8(bytes - 0x61 + 10)
default:
return nil
}
}
self.init(capacity: string.utf16.count/2)
self.init(capacity: string.utf16.count / 2)
var even = true
var byte: UInt8 = 0
for c in string.utf16 {
guard let val = decodeNibble(u: c) else { return nil }
for char in string.utf16 {
guard let val = decodeNibble(bytes: char) else { return nil }
if even {
byte = val << 4
} else {
byte += val
self.append(byte)
}
even = !even
even.toggle()
}
guard even else { return nil }
}

View File

@ -7,13 +7,12 @@
import XCTest
// swiftlint:disable force_unwrapping
class TxIdTests: XCTestCase {
func testTxIdAsString() {
let transactionId = "5cf915c5d01007c39d602e08ab59d98aba366e2fb7ac01f2cdad4bf4f8f300bb"
let expectedTxIdString = "bb00f3f8f44badcdf201acb72f6e36ba8ad959ab082e609dc30710d0c515f95c"
XCTAssertEqual(Data(fromHexEncodedString: transactionId)!.toHexStringTxId(), expectedTxIdString)
}
}

View File

@ -10,41 +10,42 @@ import Foundation
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable implicitly_unwrapped_optional force_try force_unwrapping
class WalletTests: XCTestCase {
var dbData: URL! = nil
var paramDestination: URL! = nil
var cacheData: URL! = nil
var network = ZcashNetworkBuilder.network(for: .testnet)
var seedData: Data = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")!
var seedData = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")!
override func setUp() {
super.setUp()
dbData = try! __dataDbURL()
cacheData = try! __cacheDbURL()
paramDestination = try! __documentsDirectory().appendingPathComponent("parameters")
}
override func tearDown() {
super.tearDown()
if FileManager.default.fileExists(atPath: dbData.absoluteString) {
try! FileManager.default.trashItem(at: dbData, resultingItemURL: nil)
try! FileManager.default.trashItem(at: dbData, resultingItemURL: nil)
}
}
func testWalletInitialization() throws {
let derivationTool = DerivationTool(networkType: network.networkType)
let uvk = try derivationTool.deriveUnifiedViewingKeysFromSeed(seedData.bytes, numberOfAccounts: 1)
let wallet = Initializer(cacheDbURL: try __cacheDbURL(),
dataDbURL: try __dataDbURL(),
pendingDbURL: try TestDbBuilder.pendingTransactionsDbURL(),
endpoint: LightWalletEndpointBuilder.default,
network: network,
spendParamsURL: try __spendParamsURL(),
outputParamsURL: try __outputParamsURL(),
viewingKeys: uvk,
walletBirthday: 663194)
let wallet = Initializer(
cacheDbURL: try __cacheDbURL(),
dataDbURL: try __dataDbURL(),
pendingDbURL: try TestDbBuilder.pendingTransactionsDbURL(),
endpoint: LightWalletEndpointBuilder.default,
network: network,
spendParamsURL: try __spendParamsURL(),
outputParamsURL: try __outputParamsURL(),
viewingKeys: uvk,
walletBirthday: 663194
)
let synchronizer = try SDKSynchronizer(initializer: wallet)
XCTAssertNoThrow(try synchronizer.prepare())
@ -56,7 +57,7 @@ class WalletTests: XCTestCase {
}
}
struct WalletBirthdayProvider {
enum WalletBirthdayProvider {
static var testBirthday: WalletBirthday {
WalletBirthday()
}

View File

@ -7,11 +7,13 @@
import XCTest
@testable import ZcashLightClientKit
class Z2TReceiveTests: XCTestCase {
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment?
// swiftlint:disable force_unwrapping implicitly_unwrapped_optional
class Z2TReceiveTests: XCTestCase {
// swiftlint:disable:next line_length
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" // TODO: Parameterize this from environment?
let testRecipientAddress = "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz" //TODO: Parameterize this from environment
let testRecipientAddress = "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz" // TODO: Parameterize this from environment
let sendAmount: Int64 = 1000
var birthday: BlockHeight = 663150
@ -26,18 +28,23 @@ class Z2TReceiveTests: XCTestCase {
let network = DarksideWalletDNetwork()
override func setUpWithError() throws {
try super.setUpWithError()
coordinator = try TestCoordinator(
seed: seedPhrase,
walletBirthday: birthday,
channelProvider: ChannelProvider(),
network: network
)
try coordinator.reset(saplingActivation: 663150, branchID: self.branchID, chainName: self.chainName)
}
override func tearDownWithError() throws {
try super.tearDownWithError()
NotificationCenter.default.removeObserver(self)
try coordinator.stop()
try? FileManager.default.removeItem(at: coordinator.databases.cacheDB)
try? FileManager.default.removeItem(at: coordinator.databases.dataDB)
@ -45,108 +52,116 @@ class Z2TReceiveTests: XCTestCase {
}
func subscribeToFoundTransactions() {
NotificationCenter.default.addObserver(self, selector: #selector(foundTransactions(_:)), name: .synchronizerFoundTransactions, object: nil)
NotificationCenter.default.addObserver(
self,
selector: #selector(foundTransactions(_:)),
name: .synchronizerFoundTransactions,
object: nil
)
}
@objc func foundTransactions(_ notification: Notification) {
guard let transactions = notification.userInfo?[SDKSynchronizer.NotificationKeys.foundTransactions] else {
guard notification.userInfo?[SDKSynchronizer.NotificationKeys.foundTransactions] != nil else {
XCTFail("found transactions notification is empty")
return
}
self.foundTransactionsExpectation.fulfill()
}
func testFoundTransactions() throws {
subscribeToFoundTransactions()
try FakeChainBuilder.buildChain(darksideWallet: self.coordinator.service, branchID: branchID, chainName: chainName)
let receivedTxHeight: BlockHeight = 663188
var initialTotalBalance: Int64 = -1
/*
2. applyStaged(received_Tx_height)
*/
2. applyStaged(received_Tx_height)
*/
try coordinator.applyStaged(blockheight: receivedTxHeight)
sleep(2)
let preTxExpectation = XCTestExpectation(description: "pre receive")
/*
3. sync up to received_Tx_height
*/
try coordinator.sync(completion: { (synchronizer) in
initialTotalBalance = synchronizer.initializer.getBalance()
preTxExpectation.fulfill()
}, error: self.handleError)
3. sync up to received_Tx_height
*/
try coordinator.sync(
completion: { _ in
preTxExpectation.fulfill()
},
error: self.handleError
)
wait(for: [preTxExpectation, foundTransactionsExpectation], timeout: 5)
let sendExpectation = XCTestExpectation(description: "sendToAddress")
var p: PendingTransactionEntity?
var error: Error? = nil
var pendingEntity: PendingTransactionEntity?
var error: Error?
let sendAmount: Int64 = 10000
/*
4. create transaction
*/
coordinator.synchronizer.sendToAddress(spendingKey: coordinator.spendingKeys!.first!, zatoshi: sendAmount, toAddress: testRecipientAddress, memo: "test transaction", from: 0) { (result) in
4. create transaction
*/
coordinator.synchronizer.sendToAddress(
spendingKey: coordinator.spendingKeys!.first!,
zatoshi: sendAmount,
toAddress: testRecipientAddress,
memo: "test transaction",
from: 0
) { result in
switch result {
case .success(let pending):
p = pending
pendingEntity = pending
case .failure(let e):
error = e
}
sendExpectation.fulfill()
}
wait(for: [sendExpectation], timeout: 12)
guard let pendingTx = p else {
guard pendingEntity != nil else {
XCTFail("error sending to address. Error: \(String(describing: error))")
return
}
/*
5. stage 10 empty blocks
*/
5. stage 10 empty blocks
*/
try coordinator.stageBlockCreate(height: receivedTxHeight + 1, count: 10)
let sentTxHeight = receivedTxHeight + 1
/*
6. stage sent tx at sentTxHeight
*/
6. stage sent tx at sentTxHeight
*/
guard let sentTx = try coordinator.getIncomingTransactions()?.first else {
XCTFail("sent transaction not present on Darksidewalletd")
return
}
try coordinator.stageTransaction(sentTx, at: sentTxHeight)
/*
6a. applyheight(sentTxHeight + 1 )
*/
6a. applyheight(sentTxHeight + 1 )
*/
try coordinator.applyStaged(blockheight: sentTxHeight + 1)
sleep(2)
self.foundTransactionsExpectation = XCTestExpectation(description: "inbound expectation")
/*
7. sync to sentTxHeight + 1
*/
7. sync to sentTxHeight + 1
*/
let sentTxSyncExpectation = XCTestExpectation(description: "sent tx sync expectation")
try coordinator.sync(completion: { (s) in
let pMinedHeight = s.pendingTransactions.first?.minedHeight
try coordinator.sync(completion: { synchronizer in
let pMinedHeight = synchronizer.pendingTransactions.first?.minedHeight
XCTAssertEqual(pMinedHeight, sentTxHeight)
sentTxSyncExpectation.fulfill()
}, error: self.handleError)
wait(for: [sentTxSyncExpectation, foundTransactionsExpectation], timeout: 5)
}
func handleError(_ error: Error?) {
_ = try? coordinator.stop()

View File

@ -8,14 +8,13 @@
import XCTest
import GRPC
@testable import ZcashLightClientKit
// swiftlint:disable implicitly_unwrapped_optional force_try force_unwrapping
class ZcashLightClientKitTests: XCTestCase {
var latestBlockHeight: BlockHeight!
var service: LightWalletGRPCService!
override func setUp() {
super.setUp()
service = LightWalletGRPCService(endpoint: LightWalletEndpoint(address: Constants.address, port: 9067))
@ -30,17 +29,14 @@ class ZcashLightClientKitTests: XCTestCase {
}
func testEnvironmentLaunch() {
let address = Constants.address
XCTAssertFalse(address.isEmpty, "Your \'\(Environment.lightwalletdKey)\' key is missing from your launch environment variables")
}
func testService() {
// and that it has a non-zero size
XCTAssert(latestBlockHeight > 0)
}
func testBlockRangeServiceTilLastest() {
@ -49,11 +45,10 @@ class ZcashLightClientKitTests: XCTestCase {
let startHeight = latestBlockHeight - expectedCount
let endHeight = latestBlockHeight!
var blocks = [CompactBlock]()
var blocks: [CompactBlock] = []
guard let call = try? service!.blockRange(startHeight: startHeight, endHeight: endHeight, result: {
blocks.append($0)
count += 1
}) else {
XCTFail("failed to create getBlockRange( \(startHeight) ..<= \(endHeight)")
return
@ -61,11 +56,9 @@ class ZcashLightClientKitTests: XCTestCase {
_ = try! call.status.wait()
XCTAssertEqual(expectedCount + 1, count)
}
}
class Environment {
enum Environment {
static let lightwalletdKey = "LIGHTWALLETD_ADDRESS"
}

View File

@ -9,23 +9,27 @@
import XCTest
@testable import ZcashLightClientKit
// swiftlint:disable force_unwrapping implicitly_unwrapped_optional force_try
class ZcashRustBackendTests: XCTestCase {
var dbData: URL!
var dataDbHandle = TestDbHandle(originalDb: TestDbBuilder.prePopulatedDataDbURL()!)
var cacheDbHandle = TestDbHandle(originalDb: TestDbBuilder.prePopulatedCacheDbURL()!)
let spendingKey = "secret-extended-key-test1qvpevftsqqqqpqy52ut2vv24a2qh7nsukew7qg9pq6djfwyc3xt5vaxuenshp2hhspp9qmqvdh0gs2ljpwxders5jkwgyhgln0drjqaguaenfhehz4esdl4kwlm5t9q0l6wmzcrvcf5ed6dqzvct3e2ge7f6qdvzhp02m7sp5a0qjssrwpdh7u6tq89hl3wchuq8ljq8r8rwd6xdwh3nry9at80z7amnj3s6ah4jevnvfr08gxpws523z95g6dmn4wm6l3658kd4xcq9rc0qn"
let spendingKey =
// swiftlint:disable:next line_length
"secret-extended-key-test1qvpevftsqqqqpqy52ut2vv24a2qh7nsukew7qg9pq6djfwyc3xt5vaxuenshp2hhspp9qmqvdh0gs2ljpwxders5jkwgyhgln0drjqaguaenfhehz4esdl4kwlm5t9q0l6wmzcrvcf5ed6dqzvct3e2ge7f6qdvzhp02m7sp5a0qjssrwpdh7u6tq89hl3wchuq8ljq8r8rwd6xdwh3nry9at80z7amnj3s6ah4jevnvfr08gxpws523z95g6dmn4wm6l3658kd4xcq9rc0qn"
let recipientAddress = "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6"
let zpend: Int = 500_000
let networkType = NetworkType.testnet
override func setUp() {
super.setUp()
dbData = try! __dataDbURL()
try? dataDbHandle.setUp()
}
override func tearDown() {
super.tearDown()
try? FileManager.default.removeItem(at: dbData!)
dataDbHandle.dispose()
}
@ -35,27 +39,33 @@ class ZcashRustBackendTests: XCTestCase {
XCTAssertNoThrow(try ZcashRustBackend.initDataDb(dbData: dbData!, networkType: networkType))
let _ = ZcashRustBackend.initAccountsTable(dbData: dbData!, seed: Array(seed.utf8), accounts: 1, networkType: networkType)
_ = ZcashRustBackend.initAccountsTable(dbData: dbData!, seed: Array(seed.utf8), accounts: 1, networkType: networkType)
XCTAssertNotNil(ZcashRustBackend.getLastError())
}
func testDeriveExtendedSpendingKeys() {
let seed = Array("testreferencealicetestreferencealice".utf8)
var spendingKeys: [String]? = nil
var spendingKeys: [String]?
XCTAssertNoThrow(try { spendingKeys = try ZcashRustBackend.deriveExtendedSpendingKeys(seed: seed, accounts: 1, networkType: networkType) }())
XCTAssertNotNil(spendingKeys)
XCTAssertFalse(spendingKeys?.first?.isEmpty ?? true)
}
func testDeriveExtendedFullViewingKeys() {
let seed = Array("testreferencealicetestreferencealice".utf8)
var fullViewingKeys: [String]? = nil
XCTAssertNoThrow(try { fullViewingKeys = try ZcashRustBackend.deriveExtendedFullViewingKeys(seed: seed, accounts: 1, networkType: networkType) }())
var fullViewingKeys: [String]?
XCTAssertNoThrow(
try {
fullViewingKeys = try ZcashRustBackend.deriveExtendedFullViewingKeys(
seed: seed,
accounts: 1,
networkType: networkType
)
}()
)
XCTAssertNotNil(fullViewingKeys)
XCTAssertFalse(fullViewingKeys?.first?.isEmpty ?? true)
@ -63,10 +73,9 @@ class ZcashRustBackendTests: XCTestCase {
func testDeriveExtendedFullViewingKey() {
let seed = Array("testreferencealicetestreferencealice".utf8)
var fullViewingKey: String? = nil
var fullViewingKey: String?
var spendingKeys: [String]? = nil
var spendingKeys: [String]?
XCTAssertNoThrow(try { spendingKeys = try ZcashRustBackend.deriveExtendedSpendingKeys(seed: seed, accounts: 1, networkType: networkType) }())
XCTAssertNotNil(spendingKeys)
@ -100,57 +109,81 @@ class ZcashRustBackendTests: XCTestCase {
XCTAssertEqual(addr, Optional("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc"))
XCTAssertTrue(ZcashRustBackend.scanBlocks(dbCache: cacheDb, dbData: dbData, networkType: networkType))
}
func testIsValidTransparentAddressFalse() {
var isValid: Bool? = nil
var isValid: Bool?
XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidTransparentAddress("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc", networkType: networkType) }())
XCTAssertNoThrow(
try {
isValid = try ZcashRustBackend.isValidTransparentAddress(
"ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc",
networkType: networkType
)
}()
)
if let valid = isValid {
XCTAssertFalse(valid)
} else {
XCTFail()
XCTFail("Failed as invalid")
}
}
func testIsValidTransparentAddressTrue() {
var isValid: Bool? = nil
var isValid: Bool?
XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidTransparentAddress("tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7", networkType: networkType) }())
XCTAssertNoThrow(
try {
isValid = try ZcashRustBackend.isValidTransparentAddress(
"tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7",
networkType: networkType
)
}()
)
if let valid = isValid {
XCTAssertTrue(valid)
} else {
XCTFail()
XCTFail("Failed as invalid")
}
}
func testIsValidShieldedAddressTrue() {
var isValid: Bool? = nil
var isValid: Bool?
XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidShieldedAddress("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc", networkType: networkType) }())
XCTAssertNoThrow(
try {
isValid = try ZcashRustBackend.isValidShieldedAddress(
"ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc",
networkType: networkType
)
}()
)
if let valid = isValid {
XCTAssertTrue(valid)
} else {
XCTFail()
XCTFail("Failed as invalid")
}
}
func testIsValidShieldedAddressFalse() {
var isValid: Bool? = nil
var isValid: Bool?
XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidShieldedAddress("tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7", networkType: networkType) }())
XCTAssertNoThrow(
try {
isValid = try ZcashRustBackend.isValidShieldedAddress(
"tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7",
networkType: networkType
)
}()
)
if let valid = isValid {
XCTAssertFalse(valid)
} else {
XCTFail()
XCTFail("Failed as invalid")
}
}
}

View File

@ -11,35 +11,68 @@ import GRPC
enum DarksideDataset: String {
case afterLargeReorg = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/basic-reorg/after-large-large.txt"
case afterSmallReorg = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/basic-reorg/after-small-reorg.txt"
case afterSmallReorg = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/basic-reorg/after-small-reorg.txt"
case beforeReOrg = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/basic-reorg/before-reorg.txt"
/**
see
https://github.com/zcash-hackworks/darksidewalletd-test-data/tree/master/tx-index-reorg
*/
see
https://github.com/zcash-hackworks/darksidewalletd-test-data/tree/master/tx-index-reorg
*/
case txIndexChangeBefore = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/tx-index-reorg/before-reorg.txt"
case txIndexChangeAfter = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/tx-index-reorg/after-reorg.txt"
/**
See https://github.com/zcash-hackworks/darksidewalletd-test-data/tree/master/tx-height-reorg
*/
See https://github.com/zcash-hackworks/darksidewalletd-test-data/tree/master/tx-height-reorg
*/
case txHeightReOrgBefore = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/tx-height-reorg/before-reorg.txt"
case txHeightReOrgAfter = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/tx-height-reorg/after-reorg.txt"
/*
see: https://github.com/zcash-hackworks/darksidewalletd-test-data/tree/master/tx-remove-reorg
*/
see: https://github.com/zcash-hackworks/darksidewalletd-test-data/tree/master/tx-remove-reorg
*/
case txReOrgRemovesInboundTxBefore = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/tx-remove-reorg/before-reorg.txt"
case txReOrgRemovesInboundTxAfter = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/tx-remove-reorg/after-reorg.txt"
}
class DarksideWalletService: LightWalletService {
@discardableResult func blockStream(startHeight: BlockHeight, endHeight: BlockHeight, result: @escaping (Result<GRPCResult, LightWalletServiceError>) -> Void, handler: @escaping (ZcashCompactBlock) -> Void, progress: @escaping (BlockProgressReporting) -> Void) -> CancellableCall {
return service.blockStream(startHeight: startHeight, endHeight: endHeight, result: result, handler: handler, progress: progress)
var channel: Channel
var service: LightWalletGRPCService
var darksideService: DarksideStreamerClient
init(endpoint: LightWalletEndpoint) {
self.channel = ChannelProvider().channel()
self.service = LightWalletGRPCService(endpoint: endpoint)
self.darksideService = DarksideStreamerClient(channel: channel)
}
init(service: LightWalletGRPCService) {
self.channel = ChannelProvider().channel()
self.darksideService = DarksideStreamerClient(channel: channel)
self.service = service
}
convenience init() {
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 getInfo() throws -> LightWalletdInfo {
@ -51,15 +84,18 @@ class DarksideWalletService: LightWalletService {
}
func closeConnection() {
}
func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
return []
}
func fetchUTXOs(for tAddress: String, height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) {
DispatchQueue.global().asyncAfter(deadline: .now() + 0.1){
func fetchUTXOs(
for tAddress: String,
height: BlockHeight,
result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
) {
DispatchQueue.global().asyncAfter(deadline: .now() + 0.1) {
result(.success([]))
}
}
@ -68,14 +104,18 @@ class DarksideWalletService: LightWalletService {
[]
}
func fetchUTXOs(for tAddresses: [String], height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) {
DispatchQueue.global().asyncAfter(deadline: .now() + 0.1){
func fetchUTXOs(
for tAddresses: [String],
height: BlockHeight,
result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
) {
DispatchQueue.global().asyncAfter(deadline: .now() + 0.1) {
result(.success([]))
}
}
func fetchUTXOs(for tAddress: String, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) {
DispatchQueue.global().asyncAfter(deadline: .now() + 0.1){
DispatchQueue.global().asyncAfter(deadline: .now() + 0.1) {
result(.success([]))
}
}
@ -88,28 +128,6 @@ class DarksideWalletService: LightWalletService {
service.fetchTransaction(txId: txId, result: result)
}
var channel: Channel
init(endpoint: LightWalletEndpoint) {
self.channel = ChannelProvider().channel()
self.service = LightWalletGRPCService(endpoint: endpoint)
self.darksideService = DarksideStreamerClient(channel: channel)
}
init(service: LightWalletGRPCService) {
self.channel = ChannelProvider().channel()
self.darksideService = DarksideStreamerClient(channel: channel)
self.service = service
}
convenience init() {
self.init(endpoint: LightWalletEndpointBuilder.default)
}
var service: LightWalletGRPCService
var darksideService: DarksideStreamerClient
func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void) {
service.latestBlockHeight(result: result)
}
@ -127,8 +145,8 @@ class DarksideWalletService: LightWalletService {
}
/**
Darskside lightwalletd should do a fake submission, by sending over the tx, retrieving it and including it in a new block
*/
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)
}
@ -158,11 +176,17 @@ class DarksideWalletService: LightWalletService {
}
func getIncomingTransactions() throws -> [RawTransaction]? {
var txs = [RawTransaction]()
let response = try darksideService.getIncomingTransactions(Empty(), handler: { txs.append($0) }).status.wait()
var txs: [RawTransaction] = []
let response = try darksideService.getIncomingTransactions(
Empty(),
handler: { txs.append($0) }
)
.status
.wait()
switch response.code {
case .success:
return txs.count > 0 ? txs : nil
case .ok:
return !txs.isEmpty ? txs : nil
default:
throw response
}
@ -186,9 +210,11 @@ class DarksideWalletService: LightWalletService {
}
func stageTransaction(_ rawTransaction: RawTransaction, at height: BlockHeight) throws {
var tx = rawTransaction
tx.height = UInt64(height)
_ = try darksideService.stageTransactionsStream().sendMessage(tx).wait()
var transaction = rawTransaction
transaction.height = UInt64(height)
_ = try darksideService.stageTransactionsStream()
.sendMessage(transaction)
.wait()
}
func stageTransaction(from url: String, at height: BlockHeight) throws {
@ -197,12 +223,9 @@ class DarksideWalletService: LightWalletService {
txUrl.url = url
_ = try darksideService.stageTransactions(txUrl, callOptions: nil).response.wait()
}
}
class DarksideWalletDConstants: NetworkConstants {
enum DarksideWalletDConstants: NetworkConstants {
static var saplingActivationHeight: BlockHeight {
663150
}
@ -227,9 +250,8 @@ class DarksideWalletDConstants: NetworkConstants {
ZcashSDKMainnetConstants.feeChangeHeight
}
}
class DarksideWalletDNetwork: ZcashNetwork {
var constants: NetworkConstants.Type = DarksideWalletDConstants.self
var networkType = NetworkType.mainnet
}

View File

@ -11,7 +11,9 @@ import Foundation
enum FakeChainBuilderError: Error {
case fakeHexDataConversionFailed
}
class FakeChainBuilder {
// swiftlint:disable force_unwrapping function_parameter_count
enum FakeChainBuilder {
static let someOtherTxUrl = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/transactions/t-shielded-spend.txt"
static let txMainnetBlockUrl = "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/basic-reorg/663150.txt"
@ -29,7 +31,6 @@ class FakeChainBuilder {
try darksideWallet.stageBlocksCreate(from: 663151, count: 100)
try darksideWallet.stageTransaction(from: txUrls[663174]!, at: 663174)
}
static func buildChain(darksideWallet: DarksideWalletService, branchID: String, chainName: String) throws {
@ -41,7 +42,6 @@ class FakeChainBuilder {
try darksideWallet.stageTransaction(from: txUrls[663174]!, at: 663174)
try darksideWallet.stageTransaction(from: txUrls[663188]!, at: 663188)
}
static func buildChainWithTxsFarFromEachOther(darksideWallet: DarksideWalletService, branchID: String, chainName: String, length: Int) throws {
@ -53,10 +53,8 @@ class FakeChainBuilder {
try darksideWallet.stageTransaction(from: txUrls[663188]!, at: 663188)
try darksideWallet.stageTransaction(from: txUrls[663974]!, at: 663974)
}
static func buildChain(darksideWallet: DarksideWalletService, branchID: String, chainName: String, length: Int) throws {
try darksideWallet.reset(saplingActivation: 663150, branchID: branchID, chainName: chainName)
try darksideWallet.useDataset(from: txMainnetBlockUrl)
@ -70,34 +68,49 @@ class FakeChainBuilder {
try darksideWallet.stageTransaction(from: txUrls[663953]!, at: 663953)
try darksideWallet.stageTransaction(from: txUrls[663974]!, at: 663974)
}
static func buildChain(darksideWallet: DarksideWalletService, birthday: BlockHeight, networkActivationHeight: BlockHeight, branchID: String, chainName: String, length: Int) throws {
static func buildChain(
darksideWallet: DarksideWalletService,
birthday: BlockHeight,
networkActivationHeight: BlockHeight,
branchID: String,
chainName: String,
length: Int
) throws {
try darksideWallet.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
try darksideWallet.useDataset(testnetCanopyStartBlock)
try darksideWallet.stageBlocksCreate(from: birthday + 1, count: length)
try darksideWallet.stageTransaction(from: testnetPreCanopyTx, at: networkActivationHeight - ZcashSDK.expiryOffset)
}
static func buildChainPostActivationFunds(darksideWallet: DarksideWalletService, birthday: BlockHeight, networkActivationHeight: BlockHeight, length: Int) throws {
try darksideWallet.reset(saplingActivation: birthday, branchID: "e9ff75a6" , chainName: "testnet")
try darksideWallet.reset(saplingActivation: birthday, branchID: "e9ff75a6", chainName: "testnet")
try darksideWallet.useDataset(testnetCanopyStartBlock)
try darksideWallet.stageBlocksCreate(from: birthday + 1, count: length)
try darksideWallet.stageTransaction(from: testnetPostCanopyTx, at: networkActivationHeight + 1)
}
static func buildChainMixedFunds(darksideWallet: DarksideWalletService, birthday: BlockHeight, networkActivationHeight: BlockHeight, branchID: String, chainName: String, length: Int) throws {
try buildChain(darksideWallet: darksideWallet, birthday: birthday, networkActivationHeight: networkActivationHeight, branchID: branchID, chainName: chainName, length: length)
static func buildChainMixedFunds(
darksideWallet: DarksideWalletService,
birthday: BlockHeight,
networkActivationHeight: BlockHeight,
branchID: String,
chainName: String,
length: Int
) throws {
try buildChain(
darksideWallet: darksideWallet,
birthday: birthday,
networkActivationHeight: networkActivationHeight,
branchID: branchID,
chainName: chainName,
length: length
)
try darksideWallet.stageTransaction(from: testnetPostCanopyTx, at: networkActivationHeight + ZcashSDK.expiryOffset)
}
static func buildTxUrl(for id: String) -> String {
@ -105,86 +118,85 @@ class FakeChainBuilder {
}
static var txUrls = [
663174 : buildTxUrl(for: "8f064d23c66dc36e32445e5f3b50e0f32ac3ddb78cff21fb521eb6c19c07c99a"),
663188 : buildTxUrl(for: "15a677b6770c5505fb47439361d3d3a7c21238ee1a6874fdedad18ae96850590"),
663202 : buildTxUrl(for: "d2e7be14bbb308f9d4d68de424d622cbf774226d01cd63cc6f155fafd5cd212c"),
663218 : buildTxUrl(for: "e6566be3a4f9a80035dab8e1d97e40832a639e3ea938fb7972ea2f8482ff51ce"),
663229 : buildTxUrl(for: "0821a89be7f2fc1311792c3fa1dd2171a8cdfb2effd98590cbd5ebcdcfcf491f"),
663849 : buildTxUrl(for: "c9e35e6ff444b071d63bf9bab6480409d6361760445c8a28d24179adb35c2495"),
663891 : buildTxUrl(for: "72a29d7db511025da969418880b749f7fc0fc910cdb06f52193b5fa5c0401d9d"),
663922 : buildTxUrl(for: "ff6ea36765dc29793775c7aa71de19fca039c5b5b873a0497866e9c4bc48af01"),
663938 : buildTxUrl(for: "34e507cab780546f980176f3ff2695cd404917508c7e5ee18cc1d2ff3858cb08"),
663942 : buildTxUrl(for: "6edf869063eccff3345676b0fed9f1aa6988fb2524e3d9ca7420a13cfadcd76c"),
663947 : buildTxUrl(for: "de97394ae220c28a33ba78b944e82dabec8cb404a4407650b134b3d5950358c0"),
663949 : buildTxUrl(for: "4eaa902279f8380914baf5bcc470d8b7c11d84fda809f67f517a7cb48912b87b"),
663953 : buildTxUrl(for: "e9527891b5d43d1ac72f2c0a3ac18a33dc5a0529aec04fa600616ed35f8123f8"),
663956 : buildTxUrl(for: "73c5edf8ffba774d99155121ccf07e67fbcf14284458f7e732751fea60d3bcbc"),
663974 : buildTxUrl(for: "4dcc95dd0a2f1f51bd64bb9f729b423c6de1690664a1b6614c75925e781662f7"),
664003 : buildTxUrl(for: "d2e859e8ef8ab27355c7a6caf643065d2d7a720e334c4a84943f6d1ae3919b5d"),
664012 : buildTxUrl(for: "547784f746eef2f164bbb1a56882723dde744157a21e4fdfeadee763f73fee84"),
664022 : buildTxUrl(for: "981638bb7ac08e31ee6db5c70d98ad6b137a448716b19245f9454b450c07c911"),
664037 : buildTxUrl(for: "36505ab3c78c62981c8111d143cd57dcfe6cafcb2c3cdc258b023ae5210d53f1"),
664038 : buildTxUrl(for: "0ffc55af750bb10a9e6a7e425138cc5acb5f7ddca68bf9d0c4606437bd692622"),
678828 : buildTxUrl(for: "cfd3bce9fdeeae12b99fdb977a997177e183c2312871f0454bdf61640cc03d93"),
678836 : buildTxUrl(for: "5af3bc9818e5fabcc691f319d7354cc4194f17727f6303d59a94c3e5f0daf560"),
682588 : buildTxUrl(for: "b1f566dec94048ff81306884b6ed92eb73cdb768b738d9c8cbd94babc1f0a9c9"),
683689 : buildTxUrl(for: "3b568a1547832ac28bfcaf4c269f85fd68083735790f7949aa3a548ab53acf65"),
683791 : buildTxUrl(for: "9e2eb538207ab47356a3723fd0e6f44b9349ea944d9c2d7be0d4e3a6a02c2c29"),
683795 : buildTxUrl(for: "15d2f32494271f0a60f3928e4fc79c2cea337e06fbbbe7f6fb4a0d36002a0d42"),
683809 : buildTxUrl(for: "76be7c244c37e1710bbb9f162baab265eebc8a379ad1843435ba5e7a2c21a600"),
684374 : buildTxUrl(for: "3640a35c02cf4d9e0fa178380173b193873d8a0ef4bad57dd43e7d95db450c89"),
685126 : buildTxUrl(for: "86f3457bdb8793a413c009a8a7e128b5a82723f41ebe557327bbe555fd47fbf3"),
687746 : buildTxUrl(for: "edb32a55d5fa18fc5c6bf09f5f1de198b219b6780ca71bbc4fd321b655bbfe42"),
687900 : buildTxUrl(for: "855af341c14b94fec67e5eb56bb801a59551df33e9d955982672f5f62e76f72e"),
688059 : buildTxUrl(for: "57c226f77ad01ecf833515612e7cba7abe64500fa891144c2c89c59af8c36c22"),
691540 : buildTxUrl(for: "9a74cd7f170f6c8cef04f3327fdcf63ec69dd1263f80c9bf0b3002c871950ddd"),
691593 : buildTxUrl(for: "6b64134034ec282092501f85bf8955006894dbcac402fa5e6c85ee867334cd3d"),
691632 : buildTxUrl(for: "75f2cdd2ff6a94535326abb5d9e663d53cbfa5f31ebb24b4d7e420e9440d41a2"),
692981 : buildTxUrl(for: "f98f2c75785f110203930c7fd4115019ec70af6470db1be052985b469906fe98"),
692984 : buildTxUrl(for: "67138ad7e5e97216124c2bbcda8edb7687c2cfbf5d644df2af2a86344437a661"),
692992 : buildTxUrl(for: "6cf507ab4d3255fa51679c0256a1be1d668786bd3f558000f9e90ec442514212"),
693248 : buildTxUrl(for: "d1278d74424807b830256ccbd4d7624dc9e68a50760f870a55c8e99715072ef1"),
693268 : buildTxUrl(for: "e56c84718de5dee049b31c89832f4bf1694268e2664a04df182a8797cb00b52e"),
693325 : buildTxUrl(for: "5635f48dc99adfebb0be105231b9383bd2d0df64e43a780d11620390640b8d3d"),
693398 : buildTxUrl(for: "26c41d5dbbaaa3934b37109645b0aece9600248c5f51404d1f4ea7b711ac3312"),
693460 : buildTxUrl(for: "8d381a3d993c8d424db0907bab3fef6000bc8de9efe7186846d44dd6d6a014b1"),
693475 : buildTxUrl(for: "900f2a406c1546126e1dba0e4e6ca0e092ebe697a2f7b0abee4e9771e1038f0b"),
693718 : buildTxUrl(for: "7690c8ec740c1be3c50e2aedae8bf907ac81141ae8b6a134c1811706c73f49a6"),
693736 : buildTxUrl(for: "34a4d630f120e4c1e7d2b9844c69fd4d3be71532ade1aaf7147566f05162c316"),
696005 : buildTxUrl(for: "076d30ca62082dda9a760e0d004393cd96830056c6dca643fccdbe500053e355"),
696012 : buildTxUrl(for: "e2da49325057b2232e85b0228955234f4a3538df2ebf4cd121589bac9771f6f2"),
696040 : buildTxUrl(for: "4f6ef63bd3be8338c902901daf77ab5aa23dd97c160ee91b00950accf7f0b194"),
698361 : buildTxUrl(for: "d275a9e96e6c68dfb8fe6ec3fd39737ce5fa880f86552b3ed993048373d6e8ad"),
710823 : buildTxUrl(for: "bac04ad7734628e70a57408c65403ec845bce575197e7984435976e1ac64ae4f"),
710896 : buildTxUrl(for: "56c63ef496f633418f0576cc34a0730c74023d78003b95aff731e0448c8b9203"),
711847 : buildTxUrl(for: "82439eade5d1deba7606f3db53bf33588677b1bd9765a5eb5f4d3f6980ecb3d4"),
727486 : buildTxUrl(for: "b5877c7f7dd3856bae679f7ccb37ddf3fcd2fafe72a081878ee9069fc25934cd"),
728159 : buildTxUrl(for: "5d6a0c4879a244d2c0a6e2d26c4d0d26dee5a5c1f3f13f42436253272d4b8a03"),
736102 : buildTxUrl(for: "be3a3a3fe10b9a1976410e5aaf425b24695dcdd04df926a23d9f3f8ed43178c6"),
736254 : buildTxUrl(for: "acc0685aee04f7b7c6a12c969c1646038ea4a3b940d00b28d1eaf7643602d49e"),
736262 : buildTxUrl(for: "fed00ff5cb6ee057d00ec70f1f5f1b189d591903c1e1cbde654ad39c8477808c"),
736301 : buildTxUrl(for: "f3ef9f3adedf2b66e438c9d7d878ed72886b62b70e68547bb47d5b6033519dcd"),
736574 : buildTxUrl(for: "34574442629a2378eccd216385d8bc99859e214e79265941319599130de2c69a"),
739582 : buildTxUrl(for: "71935e29127a7de0b96081f4c8a42a9c11584d83adedfaab414362a6f3d965cf"),
741148 : buildTxUrl(for: "5eff7f15b39b9ab463767b768e23f90b4a23239ed873fdfbd4afa286027f7b57"),
741154 : buildTxUrl(for: "b05c3df882ccff4f58acc1e3dbe2520213159d584bac01ff0199c37c25451430"),
741156 : buildTxUrl(for: "1a3bb3d4fece0fcde1a47ef8271511cefcdb67f2698afc2c63297fbeab2003d8"),
741158 : buildTxUrl(for: "a979dc83f55d9114dcab2eb5694bbf4fbb84602ceb27af6e287d6af8775d92c7"),
741162 : buildTxUrl(for: "23278a3c1bf03f20f67299ed0b8dc4d577909d2344f1f02971c8890c6341d79d"),
741170 : buildTxUrl(for: "db4101f3cccb1671dc1557670fa8b4e64c958008778b8ab1779a4a2969fe1153"),
741171 : buildTxUrl(for: "74a94aceedb3a22eedb0b5d450487340b3783e1d22ef47af2359c45d0804d9ff"),
741172 : buildTxUrl(for: "2899ccaea26e4c873a09965e0c268c96a86b1931d896b8622f36422d32c234c2"),
741174 : buildTxUrl(for: "819009ec1d0cfb50d30c944a41bde545ee631663af39f8a17c31255ada12de13"),
775018 : buildTxUrl(for: "85b3b64903b1873f5b7578eb2f167752b6a66ba64bb5c4cb8a4d75072219678b"),
775021 : buildTxUrl(for: "6d69d23c8db7736efdd38090c3cd032f8e68431272964157c52a924315e1a3f5"),
775267 : buildTxUrl(for: "daf24871749c8360028a19e4d82ddb0d573d7c765a894d601aa241f1e040ac5f"),
776019 : buildTxUrl(for: "f64378feb08c30b28a90f31e8cd84a932ed064108fb17a3e0aee1585ff994138"),
776158 : buildTxUrl(for: "9339a0a231f88b3067f3378c7ae70170fdf4246e0e70f442552a6e3961391b56"),
776233 : buildTxUrl(for: "c9c33e44468c1fa0ee5f9d411b43748f8882915640b3b13c6e48c56e9cdde798"),
776240 : buildTxUrl(for: "0e1c70fc67d3b9ae29a98996d4363b512d51d7b8422a6fa58f5803bebb247e7a"),
820691 : buildTxUrl(for: "1948bc40226e53d2652f593ebe4f34c5d81550eeb16fe2ed797b7ef3c1083899"),
822410 : buildTxUrl(for: "f3f8684be8d77367d099a38f30e3652410cdebe35c006d0599d86d8ec640867f"),
828933 : buildTxUrl(for: "1fd394257d1c10c8a70fb760cf73f6d0e96e61edcf1ffca6da12d733a59221a4")
663174: buildTxUrl(for: "8f064d23c66dc36e32445e5f3b50e0f32ac3ddb78cff21fb521eb6c19c07c99a"),
663188: buildTxUrl(for: "15a677b6770c5505fb47439361d3d3a7c21238ee1a6874fdedad18ae96850590"),
663202: buildTxUrl(for: "d2e7be14bbb308f9d4d68de424d622cbf774226d01cd63cc6f155fafd5cd212c"),
663218: buildTxUrl(for: "e6566be3a4f9a80035dab8e1d97e40832a639e3ea938fb7972ea2f8482ff51ce"),
663229: buildTxUrl(for: "0821a89be7f2fc1311792c3fa1dd2171a8cdfb2effd98590cbd5ebcdcfcf491f"),
663849: buildTxUrl(for: "c9e35e6ff444b071d63bf9bab6480409d6361760445c8a28d24179adb35c2495"),
663891: buildTxUrl(for: "72a29d7db511025da969418880b749f7fc0fc910cdb06f52193b5fa5c0401d9d"),
663922: buildTxUrl(for: "ff6ea36765dc29793775c7aa71de19fca039c5b5b873a0497866e9c4bc48af01"),
663938: buildTxUrl(for: "34e507cab780546f980176f3ff2695cd404917508c7e5ee18cc1d2ff3858cb08"),
663942: buildTxUrl(for: "6edf869063eccff3345676b0fed9f1aa6988fb2524e3d9ca7420a13cfadcd76c"),
663947: buildTxUrl(for: "de97394ae220c28a33ba78b944e82dabec8cb404a4407650b134b3d5950358c0"),
663949: buildTxUrl(for: "4eaa902279f8380914baf5bcc470d8b7c11d84fda809f67f517a7cb48912b87b"),
663953: buildTxUrl(for: "e9527891b5d43d1ac72f2c0a3ac18a33dc5a0529aec04fa600616ed35f8123f8"),
663956: buildTxUrl(for: "73c5edf8ffba774d99155121ccf07e67fbcf14284458f7e732751fea60d3bcbc"),
663974: buildTxUrl(for: "4dcc95dd0a2f1f51bd64bb9f729b423c6de1690664a1b6614c75925e781662f7"),
664003: buildTxUrl(for: "d2e859e8ef8ab27355c7a6caf643065d2d7a720e334c4a84943f6d1ae3919b5d"),
664012: buildTxUrl(for: "547784f746eef2f164bbb1a56882723dde744157a21e4fdfeadee763f73fee84"),
664022: buildTxUrl(for: "981638bb7ac08e31ee6db5c70d98ad6b137a448716b19245f9454b450c07c911"),
664037: buildTxUrl(for: "36505ab3c78c62981c8111d143cd57dcfe6cafcb2c3cdc258b023ae5210d53f1"),
664038: buildTxUrl(for: "0ffc55af750bb10a9e6a7e425138cc5acb5f7ddca68bf9d0c4606437bd692622"),
678828: buildTxUrl(for: "cfd3bce9fdeeae12b99fdb977a997177e183c2312871f0454bdf61640cc03d93"),
678836: buildTxUrl(for: "5af3bc9818e5fabcc691f319d7354cc4194f17727f6303d59a94c3e5f0daf560"),
682588: buildTxUrl(for: "b1f566dec94048ff81306884b6ed92eb73cdb768b738d9c8cbd94babc1f0a9c9"),
683689: buildTxUrl(for: "3b568a1547832ac28bfcaf4c269f85fd68083735790f7949aa3a548ab53acf65"),
683791: buildTxUrl(for: "9e2eb538207ab47356a3723fd0e6f44b9349ea944d9c2d7be0d4e3a6a02c2c29"),
683795: buildTxUrl(for: "15d2f32494271f0a60f3928e4fc79c2cea337e06fbbbe7f6fb4a0d36002a0d42"),
683809: buildTxUrl(for: "76be7c244c37e1710bbb9f162baab265eebc8a379ad1843435ba5e7a2c21a600"),
684374: buildTxUrl(for: "3640a35c02cf4d9e0fa178380173b193873d8a0ef4bad57dd43e7d95db450c89"),
685126: buildTxUrl(for: "86f3457bdb8793a413c009a8a7e128b5a82723f41ebe557327bbe555fd47fbf3"),
687746: buildTxUrl(for: "edb32a55d5fa18fc5c6bf09f5f1de198b219b6780ca71bbc4fd321b655bbfe42"),
687900: buildTxUrl(for: "855af341c14b94fec67e5eb56bb801a59551df33e9d955982672f5f62e76f72e"),
688059: buildTxUrl(for: "57c226f77ad01ecf833515612e7cba7abe64500fa891144c2c89c59af8c36c22"),
691540: buildTxUrl(for: "9a74cd7f170f6c8cef04f3327fdcf63ec69dd1263f80c9bf0b3002c871950ddd"),
691593: buildTxUrl(for: "6b64134034ec282092501f85bf8955006894dbcac402fa5e6c85ee867334cd3d"),
691632: buildTxUrl(for: "75f2cdd2ff6a94535326abb5d9e663d53cbfa5f31ebb24b4d7e420e9440d41a2"),
692981: buildTxUrl(for: "f98f2c75785f110203930c7fd4115019ec70af6470db1be052985b469906fe98"),
692984: buildTxUrl(for: "67138ad7e5e97216124c2bbcda8edb7687c2cfbf5d644df2af2a86344437a661"),
692992: buildTxUrl(for: "6cf507ab4d3255fa51679c0256a1be1d668786bd3f558000f9e90ec442514212"),
693248: buildTxUrl(for: "d1278d74424807b830256ccbd4d7624dc9e68a50760f870a55c8e99715072ef1"),
693268: buildTxUrl(for: "e56c84718de5dee049b31c89832f4bf1694268e2664a04df182a8797cb00b52e"),
693325: buildTxUrl(for: "5635f48dc99adfebb0be105231b9383bd2d0df64e43a780d11620390640b8d3d"),
693398: buildTxUrl(for: "26c41d5dbbaaa3934b37109645b0aece9600248c5f51404d1f4ea7b711ac3312"),
693460: buildTxUrl(for: "8d381a3d993c8d424db0907bab3fef6000bc8de9efe7186846d44dd6d6a014b1"),
693475: buildTxUrl(for: "900f2a406c1546126e1dba0e4e6ca0e092ebe697a2f7b0abee4e9771e1038f0b"),
693718: buildTxUrl(for: "7690c8ec740c1be3c50e2aedae8bf907ac81141ae8b6a134c1811706c73f49a6"),
693736: buildTxUrl(for: "34a4d630f120e4c1e7d2b9844c69fd4d3be71532ade1aaf7147566f05162c316"),
696005: buildTxUrl(for: "076d30ca62082dda9a760e0d004393cd96830056c6dca643fccdbe500053e355"),
696012: buildTxUrl(for: "e2da49325057b2232e85b0228955234f4a3538df2ebf4cd121589bac9771f6f2"),
696040: buildTxUrl(for: "4f6ef63bd3be8338c902901daf77ab5aa23dd97c160ee91b00950accf7f0b194"),
698361: buildTxUrl(for: "d275a9e96e6c68dfb8fe6ec3fd39737ce5fa880f86552b3ed993048373d6e8ad"),
710823: buildTxUrl(for: "bac04ad7734628e70a57408c65403ec845bce575197e7984435976e1ac64ae4f"),
710896: buildTxUrl(for: "56c63ef496f633418f0576cc34a0730c74023d78003b95aff731e0448c8b9203"),
711847: buildTxUrl(for: "82439eade5d1deba7606f3db53bf33588677b1bd9765a5eb5f4d3f6980ecb3d4"),
727486: buildTxUrl(for: "b5877c7f7dd3856bae679f7ccb37ddf3fcd2fafe72a081878ee9069fc25934cd"),
728159: buildTxUrl(for: "5d6a0c4879a244d2c0a6e2d26c4d0d26dee5a5c1f3f13f42436253272d4b8a03"),
736102: buildTxUrl(for: "be3a3a3fe10b9a1976410e5aaf425b24695dcdd04df926a23d9f3f8ed43178c6"),
736254: buildTxUrl(for: "acc0685aee04f7b7c6a12c969c1646038ea4a3b940d00b28d1eaf7643602d49e"),
736262: buildTxUrl(for: "fed00ff5cb6ee057d00ec70f1f5f1b189d591903c1e1cbde654ad39c8477808c"),
736301: buildTxUrl(for: "f3ef9f3adedf2b66e438c9d7d878ed72886b62b70e68547bb47d5b6033519dcd"),
736574: buildTxUrl(for: "34574442629a2378eccd216385d8bc99859e214e79265941319599130de2c69a"),
739582: buildTxUrl(for: "71935e29127a7de0b96081f4c8a42a9c11584d83adedfaab414362a6f3d965cf"),
741148: buildTxUrl(for: "5eff7f15b39b9ab463767b768e23f90b4a23239ed873fdfbd4afa286027f7b57"),
741154: buildTxUrl(for: "b05c3df882ccff4f58acc1e3dbe2520213159d584bac01ff0199c37c25451430"),
741156: buildTxUrl(for: "1a3bb3d4fece0fcde1a47ef8271511cefcdb67f2698afc2c63297fbeab2003d8"),
741158: buildTxUrl(for: "a979dc83f55d9114dcab2eb5694bbf4fbb84602ceb27af6e287d6af8775d92c7"),
741162: buildTxUrl(for: "23278a3c1bf03f20f67299ed0b8dc4d577909d2344f1f02971c8890c6341d79d"),
741170: buildTxUrl(for: "db4101f3cccb1671dc1557670fa8b4e64c958008778b8ab1779a4a2969fe1153"),
741171: buildTxUrl(for: "74a94aceedb3a22eedb0b5d450487340b3783e1d22ef47af2359c45d0804d9ff"),
741172: buildTxUrl(for: "2899ccaea26e4c873a09965e0c268c96a86b1931d896b8622f36422d32c234c2"),
741174: buildTxUrl(for: "819009ec1d0cfb50d30c944a41bde545ee631663af39f8a17c31255ada12de13"),
775018: buildTxUrl(for: "85b3b64903b1873f5b7578eb2f167752b6a66ba64bb5c4cb8a4d75072219678b"),
775021: buildTxUrl(for: "6d69d23c8db7736efdd38090c3cd032f8e68431272964157c52a924315e1a3f5"),
775267: buildTxUrl(for: "daf24871749c8360028a19e4d82ddb0d573d7c765a894d601aa241f1e040ac5f"),
776019: buildTxUrl(for: "f64378feb08c30b28a90f31e8cd84a932ed064108fb17a3e0aee1585ff994138"),
776158: buildTxUrl(for: "9339a0a231f88b3067f3378c7ae70170fdf4246e0e70f442552a6e3961391b56"),
776233: buildTxUrl(for: "c9c33e44468c1fa0ee5f9d411b43748f8882915640b3b13c6e48c56e9cdde798"),
776240: buildTxUrl(for: "0e1c70fc67d3b9ae29a98996d4363b512d51d7b8422a6fa58f5803bebb247e7a"),
820691: buildTxUrl(for: "1948bc40226e53d2652f593ebe4f34c5d81550eeb16fe2ed797b7ef3c1083899"),
822410: buildTxUrl(for: "f3f8684be8d77367d099a38f30e3652410cdebe35c006d0599d86d8ec640867f"),
828933: buildTxUrl(for: "1fd394257d1c10c8a70fb760cf73f6d0e96e61edcf1ffca6da12d733a59221a4")
]
}

View File

@ -14,15 +14,24 @@ struct LightWalletServiceMockResponse: LightWalletServiceResponse {
var errorCode: Int32
var errorMessage: String
var unknownFields: UnknownStorage
}
struct MockCancellable: CancellableCall {
func cancel() {}
}
class MockLightWalletService: LightWalletService {
var mockLightDInfo: LightWalletdInfo?
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 (BlockProgressReporting) -> Void) -> CancellableCall {
@discardableResult
func blockStream(
startHeight: BlockHeight,
endHeight: BlockHeight,
result: @escaping (Result<GRPCResult, LightWalletServiceError>) -> Void,
handler: @escaping (ZcashCompactBlock) -> Void,
progress: @escaping (BlockProgress) -> Void
) -> CancellableCall {
return MockCancellable()
}
@ -35,7 +44,6 @@ class MockLightWalletService: LightWalletService {
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
@ -45,27 +53,34 @@ class MockLightWalletService: LightWalletService {
}
func closeConnection() {
}
func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
[]
}
func fetchUTXOs(for tAddress: String, height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) {
func fetchUTXOs(
for tAddress: String,
height: BlockHeight,
result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
) {
}
func fetchUTXOs(for tAddresses: [String], height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
[]
}
func fetchUTXOs(for tAddresses: [String], height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) {
func fetchUTXOs(
for tAddresses: [String],
height: BlockHeight,
result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
) {
}
func fetchUTXOs(for tAddress: String, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) {
func fetchUTXOs(
for tAddress: String,
result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void
) {
}
private var service: LightWalletService
@ -110,7 +125,5 @@ class MockLightWalletService: LightWalletService {
}
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
}
}

View File

@ -35,7 +35,7 @@ class ZcashConsoleFakeStorage: CompactBlockRepository {
}
}
fileprivate func fakeSave(blocks: [ZcashCompactBlock]) {
private func fakeSave(blocks: [ZcashCompactBlock]) {
blocks.forEach {
LoggerProxy.debug("saving block \($0)")
self.latestBlockHeight = $0.height
@ -60,5 +60,4 @@ class ZcashConsoleFakeStorage: CompactBlockRepository {
LoggerProxy.debug("rewind to \(height)")
self.latestBlockHeight = min(self.latestBlockHeight, height)
}
}

View File

@ -6,123 +6,50 @@
//
import Foundation
@testable import ZcashLightClientKit
class MockTransactionRepository: TransactionRepository {
func findConfirmedTransactionBy(rawId: Data) throws -> ConfirmedTransactionEntity? {
nil
}
func blockForHeight(_ height: BlockHeight) throws -> Block? {
nil
}
func findConfirmedTransactions(in range: BlockRange, offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? {
nil
}
func findAll(from: ConfirmedTransactionEntity?, limit: Int) throws -> [ConfirmedTransactionEntity]? {
nil
}
func findTransactions(in range: BlockRange, limit: Int) throws -> [TransactionEntity]? {
nil
class MockTransactionRepository {
enum Kind {
case sent
case received
}
var unminedCount: Int
var receivedCount: Int
var sentCount: Int
var transactions: [ConfirmedTransactionEntity] = []
var reference: [Kind] = []
var sentTransactions: [ConfirmedTransaction] = []
var receivedTransactions: [ConfirmedTransaction] = []
var network: ZcashNetwork
var allCount: Int {
receivedCount + sentCount
}
var network: ZcashNetwork
init(unminedCount: Int,
receivedCount: Int,
sentCount: Int,
network: ZcashNetwork) {
init(
unminedCount: Int,
receivedCount: Int,
sentCount: Int,
network: ZcashNetwork
) {
self.unminedCount = unminedCount
self.receivedCount = receivedCount
self.sentCount = sentCount
self.network = network
}
func generate() {
var txArray = [ConfirmedTransactionEntity]()
var txArray: [ConfirmedTransactionEntity] = []
reference = referenceArray()
for i in 0 ..< reference.count {
txArray.append(mockTx(index: i, kind: reference[i]))
for index in 0 ..< reference.count {
txArray.append(mockTx(index: index, kind: reference[index]))
}
transactions = txArray
}
func countAll() throws -> Int {
allCount
}
func countUnmined() throws -> Int {
unminedCount
}
func findBy(id: Int) throws -> TransactionEntity? {
transactions.first(where: {$0.id == id})?.transactionEntity
}
func findBy(rawId: Data) throws -> TransactionEntity? {
transactions.first(where: {$0.rawTransactionId == rawId})?.transactionEntity
}
func findAllSentTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? {
guard let indices = reference.indices(where: { $0 == .sent }) else { return nil }
let sentTxs = indices.map { (idx) -> ConfirmedTransactionEntity in
transactions[idx]
}
return slice(txs: sentTxs, offset: offset, limit: limit)
}
func findAllReceivedTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? {
guard let indices = reference.indices(where: { $0 == .received }) else { return nil }
let receivedTxs = indices.map { (idx) -> ConfirmedTransactionEntity in
transactions[idx]
}
return slice(txs: receivedTxs, offset: offset, limit: limit)
}
func findAll(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? {
transactions
}
func lastScannedHeight() throws -> BlockHeight {
return 700000
}
func isInitialized() throws -> Bool {
true
}
func findEncodedTransactionBy(txId: Int) -> EncodedTransaction? {
nil
}
enum Kind {
case sent
case received
}
func referenceArray() -> [Kind] {
var template = [Kind]()
var template: [Kind] = []
for _ in 0 ..< sentCount {
template.append(.sent)
@ -130,10 +57,10 @@ class MockTransactionRepository: TransactionRepository {
for _ in 0 ..< receivedCount {
template.append(.received)
}
return template.shuffled()
}
func mockTx(index: Int, kind: Kind) -> ConfirmedTransactionEntity {
switch kind {
case .received:
@ -144,17 +71,41 @@ class MockTransactionRepository: TransactionRepository {
}
func mockSent(_ index: Int) -> ConfirmedTransactionEntity {
ConfirmedTransaction(toAddress: "some_address", expiryHeight: BlockHeight.max, minedHeight: randomBlockHeight(), noteId: index, blockTimeInSeconds: randomTimeInterval(), transactionIndex: index, raw: Data(), id: index, value: Int.random(in: 1 ... ZcashSDK.zatoshiPerZEC), memo: nil, rawTransactionId: Data())
ConfirmedTransaction(
toAddress: "some_address",
expiryHeight: BlockHeight.max,
minedHeight: randomBlockHeight(),
noteId: index,
blockTimeInSeconds: randomTimeInterval(),
transactionIndex: index,
raw: Data(),
id: index,
value: Int.random(in: 1 ... ZcashSDK.zatoshiPerZEC),
memo: nil,
rawTransactionId: Data()
)
}
func mockReceived(_ index: Int) -> ConfirmedTransactionEntity {
ConfirmedTransaction(toAddress: nil, expiryHeight: BlockHeight.max, minedHeight: randomBlockHeight(), noteId: index, blockTimeInSeconds: randomTimeInterval(), transactionIndex: index, raw: Data(), id: index, value: Int.random(in: 1 ... ZcashSDK.zatoshiPerZEC), memo: nil, rawTransactionId: Data())
ConfirmedTransaction(
toAddress: nil,
expiryHeight: BlockHeight.max,
minedHeight: randomBlockHeight(),
noteId: index,
blockTimeInSeconds: randomTimeInterval(),
transactionIndex: index,
raw: Data(),
id: index,
value: Int.random(in: 1 ... ZcashSDK.zatoshiPerZEC),
memo: nil,
rawTransactionId: Data()
)
}
func randomBlockHeight() -> BlockHeight {
BlockHeight.random(in: network.constants.saplingActivationHeight ... 1_000_000)
}
func randomTimeInterval() -> TimeInterval {
Double.random(in: Date().timeIntervalSince1970 - 1000000.0 ... Date().timeIntervalSince1970)
}
@ -168,18 +119,93 @@ class MockTransactionRepository: TransactionRepository {
extension MockTransactionRepository.Kind: Equatable {}
// MARK: - TransactionRepository
extension MockTransactionRepository: TransactionRepository {
func countAll() throws -> Int {
allCount
}
func countUnmined() throws -> Int {
unminedCount
}
func blockForHeight(_ height: BlockHeight) throws -> Block? {
nil
}
func findBy(id: Int) throws -> TransactionEntity? {
transactions.first(where: { $0.id == id })?.transactionEntity
}
func findBy(rawId: Data) throws -> TransactionEntity? {
transactions.first(where: { $0.rawTransactionId == rawId })?.transactionEntity
}
func findAllSentTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? {
guard let indices = reference.indices(where: { $0 == .sent }) else { return nil }
let sentTxs = indices.map { idx -> ConfirmedTransactionEntity in
transactions[idx]
}
return slice(txs: sentTxs, offset: offset, limit: limit)
}
func findAllReceivedTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? {
guard let indices = reference.indices(where: { $0 == .received }) else { return nil }
let receivedTxs = indices.map { idx -> ConfirmedTransactionEntity in
transactions[idx]
}
return slice(txs: receivedTxs, offset: offset, limit: limit)
}
func findAll(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? {
transactions
}
func findAll(from: ConfirmedTransactionEntity?, limit: Int) throws -> [ConfirmedTransactionEntity]? {
nil
}
func lastScannedHeight() throws -> BlockHeight {
return 700000
}
func isInitialized() throws -> Bool {
true
}
func findEncodedTransactionBy(txId: Int) -> EncodedTransaction? {
nil
}
func findTransactions(in range: BlockRange, limit: Int) throws -> [TransactionEntity]? {
nil
}
func findConfirmedTransactionBy(rawId: Data) throws -> ConfirmedTransactionEntity? {
nil
}
func findConfirmedTransactions(in range: BlockRange, offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? {
nil
}
}
extension Array {
func indices(where f: (_ element: Element) -> Bool) -> [Int]? {
guard self.count > 0 else { return nil }
var idx = [Int]()
for i in 0 ..< self.count {
if f(self[i]) {
idx.append(i)
func indices(where function: (_ element: Element) -> Bool) -> [Int]? {
guard !self.isEmpty else { return nil }
var idx: [Int] = []
for index in 0 ..< self.count {
if function(self[index]) {
idx.append(index)
}
}
guard idx.count > 0 else { return nil }
guard !idx.isEmpty else { return nil }
return idx
}
}

View File

@ -10,6 +10,7 @@ import Foundation
import ZcashLightClientKit
import os
// swiftlint:disable force_unwrapping print_function_usage
class SampleLogger: ZcashLightClientKit.Logger {
enum LogLevel: Int {
case debug
@ -46,8 +47,8 @@ class SampleLogger: ZcashLightClientKit.Logger {
}
func warn(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
guard level.rawValue <= LogLevel.warning.rawValue else { return }
log(level: "WARNING ⚠️", message: message, file: file, function: function, line: line)
guard level.rawValue <= LogLevel.warning.rawValue else { return }
log(level: "WARNING ⚠️", message: message, file: file, function: function, line: line)
}
func event(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
@ -66,7 +67,14 @@ class SampleLogger: ZcashLightClientKit.Logger {
case .printerLog:
print("[\(level)] \(fileName) - \(function) - line: \(line) -> \(message)")
default:
os_log("[%{public}@] %{public}@ - %{public}@ - Line: %{public}d -> %{public}@", level, fileName, String(describing: function), line, message)
os_log(
"[%{public}@] %{public}@ - %{public}@ - Line: %{public}d -> %{public}@",
level,
fileName,
String(describing: function),
line,
message
)
}
}
}

View File

@ -11,6 +11,7 @@ import GRPC
import SwiftProtobuf
@testable import ZcashLightClientKit
// swiftlint:disable function_parameter_count identifier_name
class AwfulLightWalletService: MockLightWalletService {
override func latestBlockHeight() throws -> BlockHeight {
throw LightWalletServiceError.criticalError
@ -24,7 +25,6 @@ class AwfulLightWalletService: MockLightWalletService {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
result(.failure(LightWalletServiceError.invalidBlock))
}
}
override func blockRange(_ range: CompactBlockRange, result: @escaping (Result<[ZcashCompactBlock], LightWalletServiceError>) -> Void) {
@ -33,56 +33,54 @@ class AwfulLightWalletService: MockLightWalletService {
}
}
override func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse,LightWalletServiceError>) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
result(.failure(LightWalletServiceError.invalidBlock))
}
override func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
result(.failure(LightWalletServiceError.invalidBlock))
}
}
/**
Submits a raw transaction over lightwalletd. Blocking
*/
/**
Submits a raw transaction over lightwalletd. Blocking
*/
override func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
throw LightWalletServiceError.invalidBlock
}
}
class SlightlyBadLightWalletService: MockLightWalletService {
override func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse,LightWalletServiceError>) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
override func submit(spendTransaction: Data, result: @escaping(Result<LightWalletServiceResponse, LightWalletServiceError>) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
result(.success(LightWalletServiceMockResponse.error))
}
}
}
/**
Submits a raw transaction over lightwalletd. Blocking
*/
/**
Submits a raw transaction over lightwalletd. Blocking
*/
override func submit(spendTransaction: Data) throws -> LightWalletServiceResponse {
LightWalletServiceMockResponse.error
}
}
extension LightWalletServiceMockResponse {
static var error: LightWalletServiceMockResponse {
LightWalletServiceMockResponse(errorCode: -100, errorMessage: "Ohhh this is bad dude, really bad, you lost all your internet money", unknownFields: UnknownStorage())
LightWalletServiceMockResponse(
errorCode: -100,
errorMessage: "Ohhh this is bad, really bad, you lost all your internet money",
unknownFields: UnknownStorage()
)
}
static var success: LightWalletServiceMockResponse {
LightWalletServiceMockResponse(errorCode: 0, errorMessage: "", unknownFields: UnknownStorage())
}
}
class MockRustBackend: ZcashRustBackendWelding {
static func clearUtxos(dbData: URL, address: String, sinceHeight: BlockHeight, networkType: NetworkType) throws -> Int32 {
-1
}
static func getNearestRewindHeight(dbData: URL, height: Int32, networkType: NetworkType) -> Int32 {
-1
}
@ -103,7 +101,16 @@ class MockRustBackend: ZcashRustBackendWelding {
-1
}
static func putUnspentTransparentOutput(dbData: URL, address: String, txid: [UInt8], index: Int, script: [UInt8], value: Int64, height: BlockHeight, networkType: NetworkType) throws -> Bool {
static func putUnspentTransparentOutput(
dbData: URL,
address: String,
txid: [UInt8],
index: Int,
script: [UInt8],
value: Int64,
height: BlockHeight,
networkType: NetworkType
) throws -> Bool {
false
}
@ -111,11 +118,31 @@ class MockRustBackend: ZcashRustBackendWelding {
throw RustWeldingError.genericError(message: "unimplemented")
}
static func createToAddress(dbData: URL, account: Int32, extsk: String, to: String, value: Int64, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64 {
static func createToAddress(
dbData: URL,
account: Int32,
extsk: String,
to address: String,
value: Int64,
memo: String?,
spendParamsPath: String,
outputParamsPath: String,
networkType: NetworkType
) -> Int64 {
-1
}
static func shieldFunds(dbCache: URL, dbData: URL, account: Int32, tsk: String, extsk: String, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64 {
static func shieldFunds(
dbCache: URL,
dbData: URL,
account: Int32,
tsk: String,
extsk: String,
memo: String?,
spendParamsPath: String,
outputParamsPath: String,
networkType: NetworkType
) -> Int64 {
-1
}
@ -171,12 +198,11 @@ class MockRustBackend: ZcashRustBackendWelding {
nil
}
static func consensusBranchIdFor(height: Int32, networkType: NetworkType) throws -> Int32 {
guard let c = consensusBranchID else {
guard let consensus = consensusBranchID else {
return try rustBackend.consensusBranchIdFor(height: height, networkType: networkType)
}
return c
return consensus
}
static var networkType = NetworkType.testnet
@ -225,9 +251,23 @@ class MockRustBackend: ZcashRustBackendWelding {
mockAccounts ?? rustBackend.initAccountsTable(dbData: dbData, seed: seed, accounts: accounts, networkType: networkType)
}
static func initBlocksTable(dbData: URL, height: Int32, hash: String, time: UInt32, saplingTree: String, networkType: NetworkType) throws {
static func initBlocksTable(
dbData: URL,
height: Int32,
hash: String,
time: UInt32,
saplingTree: String,
networkType: NetworkType
) throws {
if !mockDataDb {
try rustBackend.initBlocksTable(dbData: dbData, height: height, hash: hash, time: time, saplingTree: saplingTree, networkType: networkType)
try rustBackend.initBlocksTable(
dbData: dbData,
height: height,
hash: hash,
time: time,
saplingTree: saplingTree,
networkType: networkType
)
}
}
@ -263,7 +303,6 @@ class MockRustBackend: ZcashRustBackendWelding {
if attempts > 0 {
return validationResult(dbCache: dbCache, dbData: dbData, networkType: networkType)
} else {
if attempts == 0 {
return Int32(mockValidateCombinedChainFailureHeight)
} else if attempts < 0 && mockValidateCombinedChainKeepFailing {
@ -276,7 +315,7 @@ class MockRustBackend: ZcashRustBackendWelding {
return rustBackend.validateCombinedChain(dbCache: dbCache, dbData: dbData, networkType: networkType)
}
private static func validationResult(dbCache: URL, dbData: URL, networkType: NetworkType) -> Int32{
private static func validationResult(dbCache: URL, dbData: URL, networkType: NetworkType) -> Int32 {
if mockDataDb {
return -1
} else {
@ -290,7 +329,6 @@ class MockRustBackend: ZcashRustBackendWelding {
static func scanBlocks(dbCache: URL, dbData: URL, limit: UInt32, networkType: NetworkType) -> Bool {
if let rate = mockScanblocksSuccessRate {
if shouldSucceed(successRate: rate) {
return mockDataDb ? true : rustBackend.scanBlocks(dbCache: dbCache, dbData: dbData, networkType: networkType)
} else {
@ -300,8 +338,18 @@ class MockRustBackend: ZcashRustBackendWelding {
return rustBackend.scanBlocks(dbCache: dbCache, dbData: dbData, networkType: Self.networkType)
}
static func createToAddress(dbData: URL, account: Int32, extsk: String, consensusBranchId: Int32, to: String, value: Int64, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64 {
// mockCreateToAddress ?? rustBackend.createToAddress(dbData: dbData, account: account, extsk: extsk, consensusBranchId: consensusBranchId, to: to, value: value, memo: memo, spendParamsPath: spendParamsPath, outputParamsPath: outputParamsPath)
static func createToAddress(
dbData: URL,
account: Int32,
extsk: String,
consensusBranchId: Int32,
to address: String,
value: Int64,
memo: String?,
spendParamsPath: String,
outputParamsPath: String,
networkType: NetworkType
) -> Int64 {
-1
}
@ -325,5 +373,4 @@ class MockRustBackend: ZcashRustBackendWelding {
static func decryptAndStoreTransaction(dbData: URL, txBytes: [UInt8], minedHeight: Int32, networkType: NetworkType) -> Bool {
false
}
}

View File

@ -16,7 +16,11 @@ struct TestDbHandle {
init(originalDb: URL) {
self.originalDb = originalDb
self.readWriteDb = FileManager.default.temporaryDirectory.appendingPathComponent(self.originalDb.lastPathComponent.appending("_\(Date().timeIntervalSince1970)")) // avoid files clashing because crashing tests failed to remove previous ones by incrementally changing the filename
// avoid files clashing because crashing tests failed to remove previous ones by incrementally changing the filename
self.readWriteDb = FileManager.default.temporaryDirectory
.appendingPathComponent(
self.originalDb.lastPathComponent.appending("_\(Date().timeIntervalSince1970)")
)
}
func setUp() throws {
@ -32,8 +36,9 @@ struct TestDbHandle {
}
}
// This requires reference semantics, an enum cannot be used
// swiftlint:disable:next convenience_type
class TestDbBuilder {
enum TestBuilderError: Error {
case generalError
}
@ -41,18 +46,21 @@ class TestDbBuilder {
static func inMemoryCompactBlockStorage() throws -> CompactBlockStorage {
let compactBlockDao = CompactBlockStorage(connectionProvider: try InMemoryDbProvider())
try compactBlockDao.createTable()
return compactBlockDao
}
static func diskCompactBlockStorage(at url: URL) throws -> CompactBlockStorage {
let compactBlockDao = CompactBlockStorage(connectionProvider: SimpleConnectionProvider(path: url.absoluteString))
try compactBlockDao.createTable()
return compactBlockDao
}
static func pendingTransactionsDbURL() throws -> URL {
try __documentsDirectory().appendingPathComponent("pending.db")
}
static func prePopulatedCacheDbURL() -> URL? {
Bundle(for: TestDbBuilder.self).url(forResource: "cache", withExtension: "db")
}
@ -65,6 +73,7 @@ class TestDbBuilder {
let bundle = Bundle(for: TestDbBuilder.self)
guard let url = bundle.url(forResource: "ZcashSdk_Data", withExtension: "db") else { return nil }
let provider = SimpleConnectionProvider(path: url.absoluteString, readonly: true)
return provider
}
@ -85,7 +94,6 @@ class TestDbBuilder {
}
static func seed(db: CompactBlockRepository, with blockRange: CompactBlockRange) throws {
guard let blocks = StubBlockCreator.createBlockRange(blockRange) else {
throw TestBuilderError.generalError
}
@ -96,8 +104,8 @@ class TestDbBuilder {
struct InMemoryDbProvider: ConnectionProvider {
var readonly: Bool
var conn: Connection
init(readonly: Bool = false) throws {
self.readonly = readonly
self.conn = try Connection(.inMemory, readonly: readonly)
@ -108,7 +116,7 @@ struct InMemoryDbProvider: ConnectionProvider {
}
}
struct StubBlockCreator {
enum StubBlockCreator {
static func createRandomDataBlock(with height: BlockHeight) -> ZcashCompactBlock? {
guard let data = randomData(ofLength: 100) else {
LoggerProxy.debug("error creating stub block")
@ -116,9 +124,9 @@ struct StubBlockCreator {
}
return ZcashCompactBlock(height: height, data: data)
}
static func createBlockRange(_ range: CompactBlockRange) -> [ZcashCompactBlock]? {
var blocks = [ZcashCompactBlock]()
var blocks: [ZcashCompactBlock] = []
for height in range {
guard let block = createRandomDataBlock(with: height) else {
return nil
@ -136,8 +144,7 @@ struct StubBlockCreator {
return Data(bytes: &bytes, count: bytes.count)
}
LoggerProxy.debug("Status \(status)")
return nil
}
}

View File

@ -11,7 +11,9 @@ import GRPC
import ZcashLightClientKit
import XCTest
import NIO
class LightWalletEndpointBuilder {
// swiftlint:disable identifier_name
enum LightWalletEndpointBuilder {
static var `default`: LightWalletEndpoint {
LightWalletEndpoint(address: Constants.address, port: 9067, secure: false)
}
@ -29,23 +31,25 @@ class ChannelProvider {
func channel(secure: Bool = false) -> GRPCChannel {
let endpoint = LightWalletEndpointBuilder.default
let configuration = ClientConnection.Configuration(target: .hostAndPort(endpoint.host, endpoint.port), eventLoopGroup: MultiThreadedEventLoopGroup(numberOfThreads: 1), tls: secure ? .init() : nil)
let configuration = ClientConnection.Configuration(
target: .hostAndPort(endpoint.host, endpoint.port),
eventLoopGroup: MultiThreadedEventLoopGroup(numberOfThreads: 1),
tls: secure ? .init() : nil
)
return ClientConnection(configuration: configuration)
}
}
struct MockDbInit {
@discardableResult static func emptyFile(at path: String) -> Bool {
enum MockDbInit {
@discardableResult
static func emptyFile(at path: String) -> Bool {
FileManager.default.createFile(atPath: path, contents: Data("".utf8), attributes: nil)
}
static func destroy(at path: String) throws {
try FileManager.default.removeItem(atPath: path)
}
}
extension XCTestExpectation {
@ -83,7 +87,6 @@ func __outputParamsURL() throws -> URL {
}
func copyParametersToDocuments() throws -> (spend: URL, output: URL) {
let spendURL = try __documentsDirectory().appendingPathComponent("sapling-spend.params", isDirectory: false)
let outputURL = try __documentsDirectory().appendingPathComponent("sapling-output.params", isDirectory: false)
try FileManager.default.copyItem(at: try __spendParamsURL(), to: spendURL)
@ -94,37 +97,42 @@ func copyParametersToDocuments() throws -> (spend: URL, output: URL) {
func deleteParametersFromDocuments() throws {
let documents = try __documentsDirectory()
deleteParamsFrom(spend: documents.appendingPathComponent("sapling-spend.params"), output: documents.appendingPathComponent("sapling-output.params"))
deleteParamsFrom(
spend: documents.appendingPathComponent("sapling-spend.params"),
output: documents.appendingPathComponent("sapling-output.params")
)
}
func deleteParamsFrom(spend: URL, output: URL) {
func deleteParamsFrom(spend: URL, output: URL) {
try? FileManager.default.removeItem(at: spend)
try? FileManager.default.removeItem(at: output)
}
func parametersReady() -> Bool {
guard let output = try? __outputParamsURL(),
let spend = try? __spendParamsURL(),
FileManager.default.isReadableFile(atPath: output.absoluteString),
FileManager.default.isReadableFile(atPath: spend.absoluteString) else {
return false
guard
let output = try? __outputParamsURL(),
let spend = try? __spendParamsURL(),
FileManager.default.isReadableFile(atPath: output.absoluteString),
FileManager.default.isReadableFile(atPath: spend.absoluteString)
else {
return false
}
return true
}
class StubTest: XCTestCase {}
extension Bundle {
static var testBundle: Bundle {
Bundle(for: StubTest.self)
}
}
// swiftlint:disable force_unwrapping
class TestSeed {
/**
test account: "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
*/
test account: "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
*/
let seedString = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")!
func seed() -> [UInt8] {