From 90dcb0e3bbaa26e862b100f15e1f437e28155049 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 15 Mar 2024 01:27:18 +0000 Subject: [PATCH] Migrate to latest in-progress revision of Rust crates - New backend method `ZcashRustBackend.isSeedRelevantToWallet` - `ZcashRustBackend.scanBlocks` now takes a `fromState` argument. --- .../xcshareddata/swiftpm/Package.resolved | 3 +- Package.swift | 3 +- .../Error/ZcashError.swift | 6 ++ .../Error/ZcashErrorCode.swift | 2 + .../Error/ZcashErrorCodeDefinition.swift | 4 + .../Rust/ZcashRustBackend.swift | 35 ++++++++- .../Rust/ZcashRustBackendWelding.swift | 8 +- .../AutoMockable.generated.swift | 73 ++++++++++++++----- 8 files changed, 108 insertions(+), 26 deletions(-) diff --git a/Example/ZcashLightClientSample/ZcashLightClientSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Example/ZcashLightClientSample/ZcashLightClientSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 15d91fe3..ca2aa858 100644 --- a/Example/ZcashLightClientSample/ZcashLightClientSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Example/ZcashLightClientSample/ZcashLightClientSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -176,8 +176,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/zcash-hackworks/zcash-light-client-ffi", "state" : { - "revision" : "7c801be1f445402a433b32835a50d832e8a50437", - "version" : "0.6.0" + "revision" : "e4ee7f62741fa04008c8c9b7769bd58764b1a5ce" } } ], diff --git a/Package.swift b/Package.swift index f86b18e9..9123f94b 100644 --- a/Package.swift +++ b/Package.swift @@ -16,7 +16,8 @@ let package = Package( dependencies: [ .package(url: "https://github.com/grpc/grpc-swift.git", from: "1.19.1"), .package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.14.1"), - .package(url: "https://github.com/zcash-hackworks/zcash-light-client-ffi", exact: "0.6.0") + // Compiled from revision `533a7d4def586d0eda2993ad3ac4396452727158`. + .package(url: "https://github.com/zcash-hackworks/zcash-light-client-ffi", revision: "e4ee7f62741fa04008c8c9b7769bd58764b1a5ce") ], targets: [ .target( diff --git a/Sources/ZcashLightClientKit/Error/ZcashError.swift b/Sources/ZcashLightClientKit/Error/ZcashError.swift index a0a99f1f..a05f2696 100644 --- a/Sources/ZcashLightClientKit/Error/ZcashError.swift +++ b/Sources/ZcashLightClientKit/Error/ZcashError.swift @@ -321,6 +321,10 @@ public enum ZcashError: Equatable, Error { /// - `rustError` contains error generated by the rust layer. /// ZRUST0056 case rustGetWalletSummary(_ rustError: String) + /// Error from rust layer when calling ZcashRustBackend.isSeedRelevantToWallet + /// - `rustError` contains error generated by the rust layer. + /// ZRUST0057 + case rustIsSeedRelevantToWallet(_ rustError: String) /// SQLite query failed when fetching all accounts from the database. /// - `sqliteError` is error produced by SQLite library. /// ZADAO0001 @@ -676,6 +680,7 @@ public enum ZcashError: Equatable, Error { case .rustLatestCachedBlockHeight: return "Error from rust layer when calling ZcashRustBackend.latestCachedBlockHeight" case .rustScanProgressOutOfRange: return "Rust layer's call ZcashRustBackend.getScanProgress returned values that after computation are outside of allowed range 0-100%." case .rustGetWalletSummary: return "Error from rust layer when calling ZcashRustBackend.getWalletSummary" + case .rustIsSeedRelevantToWallet: return "Error from rust layer when calling ZcashRustBackend.isSeedRelevantToWallet" case .accountDAOGetAll: return "SQLite query failed when fetching all accounts from the database." case .accountDAOGetAllCantDecode: return "Fetched accounts from SQLite but can't decode them." case .accountDAOFindBy: return "SQLite query failed when seaching for accounts in the database." @@ -850,6 +855,7 @@ public enum ZcashError: Equatable, Error { case .rustLatestCachedBlockHeight: return .rustLatestCachedBlockHeight case .rustScanProgressOutOfRange: return .rustScanProgressOutOfRange case .rustGetWalletSummary: return .rustGetWalletSummary + case .rustIsSeedRelevantToWallet: return .rustIsSeedRelevantToWallet case .accountDAOGetAll: return .accountDAOGetAll case .accountDAOGetAllCantDecode: return .accountDAOGetAllCantDecode case .accountDAOFindBy: return .accountDAOFindBy diff --git a/Sources/ZcashLightClientKit/Error/ZcashErrorCode.swift b/Sources/ZcashLightClientKit/Error/ZcashErrorCode.swift index 24dbb96b..6237ebf0 100644 --- a/Sources/ZcashLightClientKit/Error/ZcashErrorCode.swift +++ b/Sources/ZcashLightClientKit/Error/ZcashErrorCode.swift @@ -175,6 +175,8 @@ public enum ZcashErrorCode: String { case rustScanProgressOutOfRange = "ZRUST0055" /// Error from rust layer when calling ZcashRustBackend.getWalletSummary case rustGetWalletSummary = "ZRUST0056" + /// Error from rust layer when calling ZcashRustBackend.isSeedRelevantToWallet + case rustIsSeedRelevantToWallet = "ZRUST0057" /// SQLite query failed when fetching all accounts from the database. case accountDAOGetAll = "ZADAO0001" /// Fetched accounts from SQLite but can't decode them. diff --git a/Sources/ZcashLightClientKit/Error/ZcashErrorCodeDefinition.swift b/Sources/ZcashLightClientKit/Error/ZcashErrorCodeDefinition.swift index 188577e7..af8cf787 100644 --- a/Sources/ZcashLightClientKit/Error/ZcashErrorCodeDefinition.swift +++ b/Sources/ZcashLightClientKit/Error/ZcashErrorCodeDefinition.swift @@ -348,6 +348,10 @@ enum ZcashErrorDefinition { /// - `rustError` contains error generated by the rust layer. // sourcery: code="ZRUST0056" case rustGetWalletSummary(_ rustError: String) + /// Error from rust layer when calling ZcashRustBackend.isSeedRelevantToWallet + /// - `rustError` contains error generated by the rust layer. + // sourcery: code="ZRUST0057" + case rustIsSeedRelevantToWallet(_ rustError: String) // MARK: - Account DAO diff --git a/Sources/ZcashLightClientKit/Rust/ZcashRustBackend.swift b/Sources/ZcashLightClientKit/Rust/ZcashRustBackend.swift index fa3b4a05..1f0af88d 100644 --- a/Sources/ZcashLightClientKit/Rust/ZcashRustBackend.swift +++ b/Sources/ZcashLightClientKit/Rust/ZcashRustBackend.swift @@ -80,6 +80,26 @@ actor ZcashRustBackend: ZcashRustBackendWelding { return ffiBinaryKeyPtr.pointee.unsafeToUnifiedSpendingKey(network: networkType) } + func isSeedRelevantToWallet(seed: [UInt8]) async throws -> Bool { + globalDBLock.lock() + let result = zcashlc_is_seed_relevant_to_wallet( + dbData.0, + dbData.1, + seed, + UInt(seed.count), + networkType.networkId + ) + globalDBLock.unlock() + + // -1 is the error sentinel. + guard result >= 0 else { + throw ZcashError.rustIsSeedRelevantToWallet(lastErrorMessage(fallback: "`isSeedRelevantToWallet` failed with unknown error")) + } + + // 0 is false, 1 is true. + return result != 0 + } + func proposeTransfer( account: Int32, to address: String, @@ -595,9 +615,20 @@ actor ZcashRustBackend: ZcashRustBackendWelding { return scanRanges } - func scanBlocks(fromHeight: Int32, limit: UInt32 = 0) async throws -> ScanSummary { + func scanBlocks(fromHeight: Int32, fromState: TreeState, limit: UInt32 = 0) async throws -> ScanSummary { + let fromStateBytes = try fromState.serializedData(partial: false).bytes + globalDBLock.lock() - let summaryPtr = zcashlc_scan_blocks(fsBlockDbRoot.0, fsBlockDbRoot.1, dbData.0, dbData.1, fromHeight, limit, networkType.networkId) + let summaryPtr = zcashlc_scan_blocks( + fsBlockDbRoot.0, + fsBlockDbRoot.1, + dbData.0, + dbData.1, + fromHeight, + fromStateBytes, + UInt(fromStateBytes.count), + limit, + networkType.networkId) globalDBLock.unlock() guard let summaryPtr else { diff --git a/Sources/ZcashLightClientKit/Rust/ZcashRustBackendWelding.swift b/Sources/ZcashLightClientKit/Rust/ZcashRustBackendWelding.swift index 8843dea1..611bd33e 100644 --- a/Sources/ZcashLightClientKit/Rust/ZcashRustBackendWelding.swift +++ b/Sources/ZcashLightClientKit/Rust/ZcashRustBackendWelding.swift @@ -41,6 +41,11 @@ protocol ZcashRustBackendWelding { /// - Throws: `rustCreateAccount`. func createAccount(seed: [UInt8], treeState: TreeState, recoverUntil: UInt32?) async throws -> UnifiedSpendingKey + /// Checks whether the given seed is relevant to any of the accounts in the wallet. + /// + /// - parameter seed: byte array of the seed + func isSeedRelevantToWallet(seed: [UInt8]) async throws -> Bool + /// Scans a transaction for any information that can be decrypted by the accounts in the wallet, and saves it to the wallet. /// - parameter tx: the transaction to decrypt /// - parameter minedHeight: height on which this transaction was mined. this is used to fetch the consensus branch ID. @@ -173,9 +178,10 @@ protocol ZcashRustBackendWelding { /// cache, an error will be signalled. /// /// - parameter fromHeight: scan starting from the given height. + /// - parameter fromState: The TreeState Protobuf object for the height prior to `fromHeight` /// - parameter limit: scan up to limit blocks. /// - Throws: `rustScanBlocks` if rust layer returns error. - func scanBlocks(fromHeight: Int32, limit: UInt32) async throws -> ScanSummary + func scanBlocks(fromHeight: Int32, fromState: TreeState, limit: UInt32) async throws -> ScanSummary /// Upserts a UTXO into the data db database /// - parameter txid: the txid bytes for the UTXO diff --git a/Tests/TestUtils/Sourcery/GeneratedMocks/AutoMockable.generated.swift b/Tests/TestUtils/Sourcery/GeneratedMocks/AutoMockable.generated.swift index 156d078a..f8606891 100644 --- a/Tests/TestUtils/Sourcery/GeneratedMocks/AutoMockable.generated.swift +++ b/Tests/TestUtils/Sourcery/GeneratedMocks/AutoMockable.generated.swift @@ -2222,6 +2222,39 @@ actor ZcashRustBackendWeldingMock: ZcashRustBackendWelding { } } + // MARK: - isSeedRelevantToWallet + + var isSeedRelevantToWalletSeedThrowableError: Error? + func setIsSeedRelevantToWalletSeedThrowableError(_ param: Error?) async { + isSeedRelevantToWalletSeedThrowableError = param + } + var isSeedRelevantToWalletSeedCallsCount = 0 + var isSeedRelevantToWalletSeedCalled: Bool { + return isSeedRelevantToWalletSeedCallsCount > 0 + } + var isSeedRelevantToWalletSeedReceivedSeed: [UInt8]? + var isSeedRelevantToWalletSeedReturnValue: Bool! + func setIsSeedRelevantToWalletSeedReturnValue(_ param: Bool) async { + isSeedRelevantToWalletSeedReturnValue = param + } + var isSeedRelevantToWalletSeedClosure: (([UInt8]) async throws -> Bool)? + func setIsSeedRelevantToWalletSeedClosure(_ param: (([UInt8]) async throws -> Bool)?) async { + isSeedRelevantToWalletSeedClosure = param + } + + func isSeedRelevantToWallet(seed: [UInt8]) async throws -> Bool { + if let error = isSeedRelevantToWalletSeedThrowableError { + throw error + } + isSeedRelevantToWalletSeedCallsCount += 1 + isSeedRelevantToWalletSeedReceivedSeed = seed + if let closure = isSeedRelevantToWalletSeedClosure { + return try await closure(seed) + } else { + return isSeedRelevantToWalletSeedReturnValue + } + } + // MARK: - decryptAndStoreTransaction var decryptAndStoreTransactionTxBytesMinedHeightThrowableError: Error? @@ -2737,34 +2770,34 @@ actor ZcashRustBackendWeldingMock: ZcashRustBackendWelding { // MARK: - scanBlocks - var scanBlocksFromHeightLimitThrowableError: Error? - func setScanBlocksFromHeightLimitThrowableError(_ param: Error?) async { - scanBlocksFromHeightLimitThrowableError = param + var scanBlocksFromHeightFromStateLimitThrowableError: Error? + func setScanBlocksFromHeightFromStateLimitThrowableError(_ param: Error?) async { + scanBlocksFromHeightFromStateLimitThrowableError = param } - var scanBlocksFromHeightLimitCallsCount = 0 - var scanBlocksFromHeightLimitCalled: Bool { - return scanBlocksFromHeightLimitCallsCount > 0 + var scanBlocksFromHeightFromStateLimitCallsCount = 0 + var scanBlocksFromHeightFromStateLimitCalled: Bool { + return scanBlocksFromHeightFromStateLimitCallsCount > 0 } - var scanBlocksFromHeightLimitReceivedArguments: (fromHeight: Int32, limit: UInt32)? - var scanBlocksFromHeightLimitReturnValue: ScanSummary! - func setScanBlocksFromHeightLimitReturnValue(_ param: ScanSummary) async { - scanBlocksFromHeightLimitReturnValue = param + var scanBlocksFromHeightFromStateLimitReceivedArguments: (fromHeight: Int32, fromState: TreeState, limit: UInt32)? + var scanBlocksFromHeightFromStateLimitReturnValue: ScanSummary! + func setScanBlocksFromHeightFromStateLimitReturnValue(_ param: ScanSummary) async { + scanBlocksFromHeightFromStateLimitReturnValue = param } - var scanBlocksFromHeightLimitClosure: ((Int32, UInt32) async throws -> ScanSummary)? - func setScanBlocksFromHeightLimitClosure(_ param: ((Int32, UInt32) async throws -> ScanSummary)?) async { - scanBlocksFromHeightLimitClosure = param + var scanBlocksFromHeightFromStateLimitClosure: ((Int32, TreeState, UInt32) async throws -> ScanSummary)? + func setScanBlocksFromHeightFromStateLimitClosure(_ param: ((Int32, TreeState, UInt32) async throws -> ScanSummary)?) async { + scanBlocksFromHeightFromStateLimitClosure = param } - func scanBlocks(fromHeight: Int32, limit: UInt32) async throws -> ScanSummary { - if let error = scanBlocksFromHeightLimitThrowableError { + func scanBlocks(fromHeight: Int32, fromState: TreeState, limit: UInt32) async throws -> ScanSummary { + if let error = scanBlocksFromHeightFromStateLimitThrowableError { throw error } - scanBlocksFromHeightLimitCallsCount += 1 - scanBlocksFromHeightLimitReceivedArguments = (fromHeight: fromHeight, limit: limit) - if let closure = scanBlocksFromHeightLimitClosure { - return try await closure(fromHeight, limit) + scanBlocksFromHeightFromStateLimitCallsCount += 1 + scanBlocksFromHeightFromStateLimitReceivedArguments = (fromHeight: fromHeight, fromState: fromState, limit: limit) + if let closure = scanBlocksFromHeightFromStateLimitClosure { + return try await closure(fromHeight, fromState, limit) } else { - return scanBlocksFromHeightLimitReturnValue + return scanBlocksFromHeightFromStateLimitReturnValue } }