SwiftLint Enabled on Test Folder
This commit is contained in:
parent
db5f02dbf9
commit
78b1f937ba
|
@ -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
|
@ -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 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 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 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 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 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 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 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)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,17 +8,21 @@
|
|||
|
||||
import XCTest
|
||||
@testable import ZcashLightClientKit
|
||||
class BlockDownloaderTests: XCTestCase {
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 uvk = UVFakeKey(
|
||||
extfvk: "zxviewtestsapling1qw88ayg8qqqqpqyhg7jnh9mlldejfqwu46pm40ruwstd8znq3v3l4hjf33qcu2a5e36katshcfhcxhzgyfugj2lkhmt40j45cv38rv3frnghzkxcx73k7m7afw9j7ujk7nm4dx5mv02r26umxqgar7v3x390w2h3crqqgjsjly7jy4vtwzrmustm5yudpgcydw7x78awca8wqjvkqj8p8e3ykt7lrgd7xf92fsfqjs5vegfsja4ekzpfh5vtccgvs5747xqm6qflmtqpr8s9u", // swiftlint:disable:this line_length
|
||||
extpub: "02075a7f5f7507d64022dad5954849f216b0f1b09b2d588be663d8e7faeb5aaf61"
|
||||
)
|
||||
|
||||
|
||||
var walletBirthDay = WalletBirthday.birthday(with: 1386000, network: ZcashNetworkBuilder.network(for: .testnet))
|
||||
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)
|
||||
operationQueue.addOperations(
|
||||
[downloadOperation, scanOperation, latestScannedBlockOperation],
|
||||
waitUntilFinished: false
|
||||
)
|
||||
|
||||
|
||||
wait(for: [downloadStartedExpect, downloadExpect, scanStartedExpect, scanExpect,latestScannedBlockExpect], timeout: 10, enforceOrder: true)
|
||||
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
|
||||
|
|
|
@ -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))")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,13 @@
|
|||
|
||||
import XCTest
|
||||
@testable import ZcashLightClientKit
|
||||
class CompactBlockProcessorTests: XCTestCase {
|
||||
|
||||
let processorConfig = CompactBlockProcessor.Configuration.standard(for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight)
|
||||
// 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
|
||||
)
|
||||
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)
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,15 @@
|
|||
//
|
||||
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
||||
|
||||
|
||||
import XCTest
|
||||
@testable import ZcashLightClientKit
|
||||
class CompactBlockReorgTests: XCTestCase {
|
||||
|
||||
let processorConfig = CompactBlockProcessor.Configuration.standard(for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.saplingActivationHeight)
|
||||
// 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
|
||||
)
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,12 +8,13 @@
|
|||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
// swiftlint:disable force_try
|
||||
@testable import ZcashLightClientKit
|
||||
class CompactBlockStorageTests: XCTestCase {
|
||||
|
||||
let network = ZcashNetworkBuilder.network(for: .testnet)
|
||||
var compactBlockDao: CompactBlockRepository = try! TestDbBuilder.inMemoryCompactBlockStorage()
|
||||
|
||||
let network = ZcashNetworkBuilder.network(for: .testnet)
|
||||
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)")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,11 +8,14 @@
|
|||
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
|
||||
|
@ -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)
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,12 +9,14 @@
|
|||
import XCTest
|
||||
import SQLite
|
||||
@testable import ZcashLightClientKit
|
||||
class DownloadOperationTests: XCTestCase {
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
||||
XCTAssertFalse(try ZcashRustBackend.isValidShieldedAddress(ZaddrWithNullBytes, networkType: networkType))
|
||||
func testZaddrNullBytes() throws {
|
||||
// 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))
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
|
|
@ -7,13 +7,20 @@
|
|||
|
||||
import XCTest
|
||||
@testable import ZcashLightClientKit
|
||||
class PagedTransactionRepositoryTests: XCTestCase {
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,22 +7,24 @@
|
|||
|
||||
import XCTest
|
||||
@testable import ZcashLightClientKit
|
||||
|
||||
// swiftlint:disable force_try force_unwrapping implicitly_unwrapped_optional
|
||||
class PendingTransactionRepositoryTests: XCTestCase {
|
||||
let dbUrl = try! TestDbBuilder.pendingTransactionsDbURL()
|
||||
let recipientAddress = "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6"
|
||||
|
||||
var pendingRepository: PendingTransactionRepository!
|
||||
|
||||
let dbUrl = try! TestDbBuilder.pendingTransactionsDbURL()
|
||||
|
||||
let recipientAddress = "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6"
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,10 +7,14 @@
|
|||
|
||||
import XCTest
|
||||
@testable import ZcashLightClientKit
|
||||
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
|
||||
// swiftlint:disable implicitly_unwrapped_optional
|
||||
class PendingTransactionUpdatesTest: XCTestCase {
|
||||
// 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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 = "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"
|
||||
let txFromAndroidSDK =
|
||||
// swiftlint:disable:next line_length
|
||||
"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"
|
||||
|
||||
let txBase64String = "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"
|
||||
let txBase64String =
|
||||
// swiftlint:disable:next line_length
|
||||
"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"
|
||||
}
|
||||
|
|
|
@ -7,61 +7,69 @@
|
|||
|
||||
import XCTest
|
||||
@testable import ZcashLightClientKit
|
||||
|
||||
/**
|
||||
basic reorg test. Scan, get a reorg and then reach latest height.
|
||||
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
|
||||
*/
|
||||
* 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 {
|
||||
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 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)")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,24 +7,31 @@
|
|||
|
||||
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,
|
||||
|
@ -32,23 +39,27 @@ class RewindRescanTests: XCTestCase {
|
|||
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)
|
||||
|
||||
|
@ -192,13 +211,15 @@ 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)
|
||||
}
|
||||
|
|
|
@ -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]()
|
||||
override func setUpWithError() throws {
|
||||
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)
|
||||
|
||||
|
@ -96,35 +107,33 @@ class SychronizerDarksideTests: XCTestCase {
|
|||
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -99,12 +119,10 @@ class TransactionEnhancementTests: XCTestCase {
|
|||
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)
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -7,37 +7,39 @@
|
|||
|
||||
import XCTest
|
||||
@testable import ZcashLightClientKit
|
||||
class TransactionRepositoryTests: XCTestCase {
|
||||
|
||||
// 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 }
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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==")!
|
||||
override func setUp() {
|
||||
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()
|
||||
}
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
|
||||
import XCTest
|
||||
@testable import ZcashLightClientKit
|
||||
|
||||
// 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?
|
||||
|
||||
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,6 +28,7 @@ class Z2TReceiveTests: XCTestCase {
|
|||
let network = DarksideWalletDNetwork()
|
||||
|
||||
override func setUpWithError() throws {
|
||||
try super.setUpWithError()
|
||||
|
||||
coordinator = try TestCoordinator(
|
||||
seed: seedPhrase,
|
||||
|
@ -33,11 +36,15 @@ class Z2TReceiveTests: XCTestCase {
|
|||
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,109 +52,117 @@ 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()
|
||||
guard let testError = error else {
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,84 +11,37 @@ 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)
|
||||
}
|
||||
|
||||
func getInfo() throws -> LightWalletdInfo {
|
||||
try service.getInfo()
|
||||
}
|
||||
|
||||
func getInfo(result: @escaping (Result<LightWalletdInfo, LightWalletServiceError>) -> Void) {
|
||||
service.getInfo(result: result)
|
||||
}
|
||||
|
||||
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){
|
||||
result(.success([]))
|
||||
}
|
||||
}
|
||||
|
||||
func fetchUTXOs(for tAddresses: [String], height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
||||
[]
|
||||
}
|
||||
|
||||
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){
|
||||
result(.success([]))
|
||||
}
|
||||
}
|
||||
|
||||
func fetchTransaction(txId: Data) throws -> TransactionEntity {
|
||||
try service.fetchTransaction(txId: txId)
|
||||
}
|
||||
|
||||
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
|
||||
service.fetchTransaction(txId: txId, result: result)
|
||||
}
|
||||
|
||||
var channel: Channel
|
||||
var service: LightWalletGRPCService
|
||||
var darksideService: DarksideStreamerClient
|
||||
|
||||
init(endpoint: LightWalletEndpoint) {
|
||||
self.channel = ChannelProvider().channel()
|
||||
self.service = LightWalletGRPCService(endpoint: endpoint)
|
||||
|
@ -101,14 +54,79 @@ class DarksideWalletService: LightWalletService {
|
|||
self.service = service
|
||||
}
|
||||
|
||||
|
||||
|
||||
convenience init() {
|
||||
self.init(endpoint: LightWalletEndpointBuilder.default)
|
||||
}
|
||||
|
||||
var service: LightWalletGRPCService
|
||||
var darksideService: DarksideStreamerClient
|
||||
@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 {
|
||||
try service.getInfo()
|
||||
}
|
||||
|
||||
func getInfo(result: @escaping (Result<LightWalletdInfo, LightWalletServiceError>) -> Void) {
|
||||
service.getInfo(result: result)
|
||||
}
|
||||
|
||||
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) {
|
||||
result(.success([]))
|
||||
}
|
||||
}
|
||||
|
||||
func fetchUTXOs(for tAddresses: [String], height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
|
||||
[]
|
||||
}
|
||||
|
||||
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) {
|
||||
result(.success([]))
|
||||
}
|
||||
}
|
||||
|
||||
func fetchTransaction(txId: Data) throws -> TransactionEntity {
|
||||
try service.fetchTransaction(txId: txId)
|
||||
}
|
||||
|
||||
func fetchTransaction(txId: Data, result: @escaping (Result<TransactionEntity, LightWalletServiceError>) -> Void) {
|
||||
service.fetchTransaction(txId: txId, result: result)
|
||||
}
|
||||
|
||||
func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void) {
|
||||
service.latestBlockHeight(result: result)
|
||||
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
]
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,49 +6,33 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@testable import ZcashLightClientKit
|
||||
|
||||
class MockTransactionRepository: TransactionRepository {
|
||||
func findConfirmedTransactionBy(rawId: Data) throws -> ConfirmedTransactionEntity? {
|
||||
nil
|
||||
class MockTransactionRepository {
|
||||
enum Kind {
|
||||
case sent
|
||||
case received
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
@ -56,15 +40,87 @@ class MockTransactionRepository: TransactionRepository {
|
|||
}
|
||||
|
||||
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 referenceArray() -> [Kind] {
|
||||
var template: [Kind] = []
|
||||
|
||||
for _ in 0 ..< sentCount {
|
||||
template.append(.sent)
|
||||
}
|
||||
for _ in 0 ..< receivedCount {
|
||||
template.append(.received)
|
||||
}
|
||||
|
||||
return template.shuffled()
|
||||
}
|
||||
|
||||
func mockTx(index: Int, kind: Kind) -> ConfirmedTransactionEntity {
|
||||
switch kind {
|
||||
case .received:
|
||||
return mockReceived(index)
|
||||
case .sent:
|
||||
return mockSent(index)
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
func randomBlockHeight() -> BlockHeight {
|
||||
BlockHeight.random(in: network.constants.saplingActivationHeight ... 1_000_000)
|
||||
}
|
||||
|
||||
func randomTimeInterval() -> TimeInterval {
|
||||
Double.random(in: Date().timeIntervalSince1970 - 1000000.0 ... Date().timeIntervalSince1970)
|
||||
}
|
||||
|
||||
func slice(txs: [ConfirmedTransactionEntity], offset: Int, limit: Int) -> [ConfirmedTransactionEntity] {
|
||||
guard offset < txs.count else { return [] }
|
||||
|
||||
return Array(txs[offset ..< min(offset + limit, txs.count - offset)])
|
||||
}
|
||||
}
|
||||
|
||||
extension MockTransactionRepository.Kind: Equatable {}
|
||||
|
||||
// MARK: - TransactionRepository
|
||||
extension MockTransactionRepository: TransactionRepository {
|
||||
func countAll() throws -> Int {
|
||||
allCount
|
||||
}
|
||||
|
@ -73,30 +129,34 @@ class MockTransactionRepository: TransactionRepository {
|
|||
unminedCount
|
||||
}
|
||||
|
||||
func blockForHeight(_ height: BlockHeight) throws -> Block? {
|
||||
nil
|
||||
}
|
||||
|
||||
func findBy(id: Int) throws -> TransactionEntity? {
|
||||
transactions.first(where: {$0.id == id})?.transactionEntity
|
||||
transactions.first(where: { $0.id == id })?.transactionEntity
|
||||
}
|
||||
|
||||
func findBy(rawId: Data) throws -> TransactionEntity? {
|
||||
transactions.first(where: {$0.rawTransactionId == rawId})?.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
|
||||
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 }
|
||||
guard let indices = reference.indices(where: { $0 == .received }) else { return nil }
|
||||
|
||||
let receivedTxs = indices.map { idx -> ConfirmedTransactionEntity in
|
||||
transactions[idx]
|
||||
}
|
||||
|
||||
let receivedTxs = indices.map { (idx) -> ConfirmedTransactionEntity in
|
||||
transactions[idx]
|
||||
}
|
||||
return slice(txs: receivedTxs, offset: offset, limit: limit)
|
||||
}
|
||||
|
||||
|
@ -104,6 +164,10 @@ class MockTransactionRepository: TransactionRepository {
|
|||
transactions
|
||||
}
|
||||
|
||||
func findAll(from: ConfirmedTransactionEntity?, limit: Int) throws -> [ConfirmedTransactionEntity]? {
|
||||
nil
|
||||
}
|
||||
|
||||
func lastScannedHeight() throws -> BlockHeight {
|
||||
return 700000
|
||||
}
|
||||
|
@ -116,70 +180,32 @@ class MockTransactionRepository: TransactionRepository {
|
|||
nil
|
||||
}
|
||||
|
||||
enum Kind {
|
||||
case sent
|
||||
case received
|
||||
func findTransactions(in range: BlockRange, limit: Int) throws -> [TransactionEntity]? {
|
||||
nil
|
||||
}
|
||||
|
||||
func referenceArray() -> [Kind] {
|
||||
var template = [Kind]()
|
||||
|
||||
for _ in 0 ..< sentCount {
|
||||
template.append(.sent)
|
||||
}
|
||||
for _ in 0 ..< receivedCount {
|
||||
template.append(.received)
|
||||
}
|
||||
return template.shuffled()
|
||||
func findConfirmedTransactionBy(rawId: Data) throws -> ConfirmedTransactionEntity? {
|
||||
nil
|
||||
}
|
||||
|
||||
|
||||
func mockTx(index: Int, kind: Kind) -> ConfirmedTransactionEntity {
|
||||
switch kind {
|
||||
case .received:
|
||||
return mockReceived(index)
|
||||
case .sent:
|
||||
return mockSent(index)
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
func randomBlockHeight() -> BlockHeight {
|
||||
BlockHeight.random(in: network.constants.saplingActivationHeight ... 1_000_000)
|
||||
}
|
||||
func randomTimeInterval() -> TimeInterval {
|
||||
Double.random(in: Date().timeIntervalSince1970 - 1000000.0 ... Date().timeIntervalSince1970)
|
||||
}
|
||||
|
||||
func slice(txs: [ConfirmedTransactionEntity], offset: Int, limit: Int) -> [ConfirmedTransactionEntity] {
|
||||
guard offset < txs.count else { return [] }
|
||||
|
||||
return Array(txs[offset ..< min(offset + limit, txs.count - offset)])
|
||||
func findConfirmedTransactions(in range: BlockRange, offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]? {
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
extension MockTransactionRepository.Kind: Equatable {}
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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]()
|
||||
static func createBlockRange(_ range: CompactBlockRange) -> [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
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
return ClientConnection(configuration: configuration)
|
||||
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] {
|
||||
|
|
Loading…
Reference in New Issue