Merge pull request #1187 from zcash/rust-checkpoint-and-memo-bugfixes

Update Rust dependencies with checkpoint and memo bugfixes
This commit is contained in:
Lukas Korba 2023-08-09 13:16:16 +02:00 committed by GitHub
commit 84620ed747
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 117 additions and 133 deletions

View File

@ -158,7 +158,7 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/zcash-hackworks/zcash-light-client-ffi",
"state" : {
"revision" : "7718b764027c2a4b9f654ed0b712b87ce881348f"
"revision" : "728cede1b36eb24c5c6a41e509a0358c1bd97f9c"
}
}
],

View File

@ -104,7 +104,7 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/zcash-hackworks/zcash-light-client-ffi",
"state" : {
"revision" : "7718b764027c2a4b9f654ed0b712b87ce881348f"
"revision" : "728cede1b36eb24c5c6a41e509a0358c1bd97f9c"
}
}
],

View File

@ -16,7 +16,7 @@ let package = Package(
dependencies: [
.package(url: "https://github.com/grpc/grpc-swift.git", from: "1.14.0"),
.package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.14.1"),
.package(url: "https://github.com/zcash-hackworks/zcash-light-client-ffi", revision: "7718b764027c2a4b9f654ed0b712b87ce881348f")
.package(url: "https://github.com/zcash-hackworks/zcash-light-client-ffi", revision: "728cede1b36eb24c5c6a41e509a0358c1bd97f9c")
],
targets: [
.target(

View File

@ -291,6 +291,9 @@ public enum ZcashError: Equatable, Error {
/// - `rustError` contains error generated by the rust layer.
/// ZRUST0049
case rustSuggestScanRanges(_ rustError: String)
/// Invalid transaction ID length when calling ZcashRustBackend.getMemo
/// ZRUST0050
case rustGetMemoInvalidTxIdLength
/// SQLite query failed when fetching all accounts from the database.
/// - `sqliteError` is error produced by SQLite library.
/// ZADAO0001
@ -624,6 +627,7 @@ public enum ZcashError: Equatable, Error {
case .rustPutSaplingSubtreeRoots: return "Error from rust layer when calling ZcashRustBackend.putSaplingSubtreeRoots"
case .rustUpdateChainTip: return "Error from rust layer when calling ZcashRustBackend.updateChainTip"
case .rustSuggestScanRanges: return "Error from rust layer when calling ZcashRustBackend.suggestScanRanges"
case .rustGetMemoInvalidTxIdLength: return "txId must be 32 bytes"
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."
@ -786,6 +790,7 @@ public enum ZcashError: Equatable, Error {
case .rustPutSaplingSubtreeRoots: return .rustPutSaplingSubtreeRoots
case .rustUpdateChainTip: return .rustUpdateChainTip
case .rustSuggestScanRanges: return .rustSuggestScanRanges
case .rustGetMemoInvalidTxIdLength: return .rustGetMemoInvalidTxIdLength
case .accountDAOGetAll: return .accountDAOGetAll
case .accountDAOGetAllCantDecode: return .accountDAOGetAllCantDecode
case .accountDAOFindBy: return .accountDAOFindBy

View File

@ -161,6 +161,8 @@ public enum ZcashErrorCode: String {
case rustUpdateChainTip = "ZRUST0048"
/// Error from rust layer when calling ZcashRustBackend.suggestScanRanges
case rustSuggestScanRanges = "ZRUST0049"
/// Invalid transaction ID length when calling ZcashRustBackend.getMemo
case rustGetMemoInvalidTxIdLength = "ZRUST0050"
/// SQLite query failed when fetching all accounts from the database.
case accountDAOGetAll = "ZADAO0001"
/// Fetched accounts from SQLite but can't decode them.

View File

@ -70,31 +70,38 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
to address: String,
value: Int64,
memo: MemoBytes?
) async throws -> Int64 {
let result = usk.bytes.withUnsafeBufferPointer { uskPtr in
zcashlc_create_to_address(
dbData.0,
dbData.1,
uskPtr.baseAddress,
UInt(usk.bytes.count),
[CChar](address.utf8CString),
value,
memo?.bytes,
spendParamsPath.0,
spendParamsPath.1,
outputParamsPath.0,
outputParamsPath.1,
networkType.networkId,
minimumConfirmations,
useZIP317Fees
)
) async throws -> Data {
var contiguousTxIdBytes = ContiguousArray<UInt8>([UInt8](repeating: 0x0, count: 32))
let success = contiguousTxIdBytes.withUnsafeMutableBufferPointer { txIdBytePtr in
usk.bytes.withUnsafeBufferPointer { uskPtr in
zcashlc_create_to_address(
dbData.0,
dbData.1,
uskPtr.baseAddress,
UInt(usk.bytes.count),
[CChar](address.utf8CString),
value,
memo?.bytes,
spendParamsPath.0,
spendParamsPath.1,
outputParamsPath.0,
outputParamsPath.1,
networkType.networkId,
minimumConfirmations,
useZIP317Fees,
txIdBytePtr.baseAddress
)
}
}
guard result > 0 else {
guard success else {
throw ZcashError.rustCreateToAddress(lastErrorMessage(fallback: "`createToAddress` failed with unknown error"))
}
return result
return contiguousTxIdBytes.withUnsafeBufferPointer { txIdBytePtr in
Data(txIdBytePtr)
}
}
func decryptAndStoreTransaction(txBytes: [UInt8], minedHeight: Int32) async throws {
@ -179,25 +186,16 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
return UnifiedAddress(validatedEncoding: address, networkType: networkType)
}
func getReceivedMemo(idNote: Int64) async -> Memo? {
func getMemo(txId: Data, outputIndex: UInt16) async throws -> Memo? {
guard txId.count == 32 else {
throw ZcashError.rustGetMemoInvalidTxIdLength
}
var contiguousMemoBytes = ContiguousArray<UInt8>(MemoBytes.empty().bytes)
var success = false
contiguousMemoBytes.withUnsafeMutableBufferPointer { memoBytePtr in
success = zcashlc_get_received_memo(dbData.0, dbData.1, idNote, memoBytePtr.baseAddress, networkType.networkId)
}
guard success else { return nil }
return (try? MemoBytes(contiguousBytes: contiguousMemoBytes)).flatMap { try? $0.intoMemo() }
}
func getSentMemo(idNote: Int64) async -> Memo? {
var contiguousMemoBytes = ContiguousArray<UInt8>(MemoBytes.empty().bytes)
var success = false
contiguousMemoBytes.withUnsafeMutableBytes { memoBytePtr in
success = zcashlc_get_sent_memo(dbData.0, dbData.1, idNote, memoBytePtr.baseAddress, networkType.networkId)
success = zcashlc_get_memo(dbData.0, dbData.1, txId.bytes, outputIndex, memoBytePtr.baseAddress, networkType.networkId)
}
guard success else { return nil }
@ -607,30 +605,37 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
usk: UnifiedSpendingKey,
memo: MemoBytes?,
shieldingThreshold: Zatoshi
) async throws -> Int64 {
let result = usk.bytes.withUnsafeBufferPointer { uskBuffer in
zcashlc_shield_funds(
dbData.0,
dbData.1,
uskBuffer.baseAddress,
UInt(usk.bytes.count),
memo?.bytes,
UInt64(shieldingThreshold.amount),
spendParamsPath.0,
spendParamsPath.1,
outputParamsPath.0,
outputParamsPath.1,
networkType.networkId,
minimumConfirmations,
useZIP317Fees
)
) async throws -> Data {
var contiguousTxIdBytes = ContiguousArray<UInt8>([UInt8](repeating: 0x0, count: 32))
let success = contiguousTxIdBytes.withUnsafeMutableBufferPointer { txIdBytePtr in
usk.bytes.withUnsafeBufferPointer { uskBuffer in
zcashlc_shield_funds(
dbData.0,
dbData.1,
uskBuffer.baseAddress,
UInt(usk.bytes.count),
memo?.bytes,
UInt64(shieldingThreshold.amount),
spendParamsPath.0,
spendParamsPath.1,
outputParamsPath.0,
outputParamsPath.1,
networkType.networkId,
minimumConfirmations,
useZIP317Fees,
txIdBytePtr.baseAddress
)
}
}
guard result > 0 else {
guard success else {
throw ZcashError.rustShieldFunds(lastErrorMessage(fallback: "`shieldFunds` failed with unknown error"))
}
return result
return contiguousTxIdBytes.withUnsafeBufferPointer { txIdBytePtr in
Data(txIdBytePtr)
}
}
nonisolated func consensusBranchIdFor(height: Int32) throws -> Int32 {

View File

@ -50,7 +50,7 @@ protocol ZcashRustBackendWelding {
to address: String,
value: Int64,
memo: MemoBytes?
) async throws -> Int64
) async throws -> Data
/// 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
@ -89,14 +89,10 @@ protocol ZcashRustBackendWelding {
/// - `rustGetNextAvailableAddressInvalidAddress` if generated unified address isn't valid.
func getNextAvailableAddress(account: Int32) async throws -> UnifiedAddress
/// Get received memo from note.
/// - parameter idNote: note_id of note where the memo is located
func getReceivedMemo(idNote: Int64) async -> Memo?
/// Get sent memo from note.
/// - parameter idNote: note_id of note where the memo is located
/// - Returns: a `Memo` if any
func getSentMemo(idNote: Int64) async -> Memo?
/// Get memo from note.
/// - parameter txId: ID of transaction containing the note
/// - parameter outputIndex: output index of note
func getMemo(txId: Data, outputIndex: UInt16) async throws -> Memo?
/// Get the verified cached transparent balance for the given address
/// - parameter account; the account index to query
@ -223,7 +219,7 @@ protocol ZcashRustBackendWelding {
usk: UnifiedSpendingKey,
memo: MemoBytes?,
shieldingThreshold: Zatoshi
) async throws -> Int64
) async throws -> Data
/// Gets the consensus branch id for the given height
/// - Parameter height: the height you what to know the branch id for

View File

@ -71,7 +71,7 @@ class WalletTransactionEncoder: TransactionEncoder {
)
logger.debug("transaction id: \(txId)")
return try await repository.find(id: txId)
return try await repository.find(rawID: txId)
}
func createSpend(
@ -80,7 +80,7 @@ class WalletTransactionEncoder: TransactionEncoder {
to address: String,
memoBytes: MemoBytes?,
from accountIndex: Int
) async throws -> Int {
) async throws -> Data {
guard ensureParams(spend: self.spendParamsURL, output: self.outputParamsURL) else {
throw ZcashError.walletTransEncoderCreateTransactionMissingSaplingParams
}
@ -92,7 +92,7 @@ class WalletTransactionEncoder: TransactionEncoder {
memo: memoBytes
)
return Int(txId)
return txId
}
func createShieldingTransaction(
@ -109,7 +109,7 @@ class WalletTransactionEncoder: TransactionEncoder {
)
logger.debug("transaction id: \(txId)")
return try await repository.find(id: txId)
return try await repository.find(rawID: txId)
}
func createShieldingSpend(
@ -117,7 +117,7 @@ class WalletTransactionEncoder: TransactionEncoder {
shieldingThreshold: Zatoshi,
memo: MemoBytes?,
accountIndex: Int
) async throws -> Int {
) async throws -> Data {
guard ensureParams(spend: self.spendParamsURL, output: self.outputParamsURL) else {
throw ZcashError.walletTransEncoderShieldFundsMissingSaplingParams
}
@ -128,7 +128,7 @@ class WalletTransactionEncoder: TransactionEncoder {
shieldingThreshold: shieldingThreshold
)
return Int(txId)
return txId
}
func submit(

View File

@ -2097,16 +2097,16 @@ actor ZcashRustBackendWeldingMock: ZcashRustBackendWelding {
return createToAddressUskToValueMemoCallsCount > 0
}
var createToAddressUskToValueMemoReceivedArguments: (usk: UnifiedSpendingKey, address: String, value: Int64, memo: MemoBytes?)?
var createToAddressUskToValueMemoReturnValue: Int64!
func setCreateToAddressUskToValueMemoReturnValue(_ param: Int64) async {
var createToAddressUskToValueMemoReturnValue: Data!
func setCreateToAddressUskToValueMemoReturnValue(_ param: Data) async {
createToAddressUskToValueMemoReturnValue = param
}
var createToAddressUskToValueMemoClosure: ((UnifiedSpendingKey, String, Int64, MemoBytes?) async throws -> Int64)?
func setCreateToAddressUskToValueMemoClosure(_ param: ((UnifiedSpendingKey, String, Int64, MemoBytes?) async throws -> Int64)?) async {
var createToAddressUskToValueMemoClosure: ((UnifiedSpendingKey, String, Int64, MemoBytes?) async throws -> Data)?
func setCreateToAddressUskToValueMemoClosure(_ param: ((UnifiedSpendingKey, String, Int64, MemoBytes?) async throws -> Data)?) async {
createToAddressUskToValueMemoClosure = param
}
func createToAddress(usk: UnifiedSpendingKey, to address: String, value: Int64, memo: MemoBytes?) async throws -> Int64 {
func createToAddress(usk: UnifiedSpendingKey, to address: String, value: Int64, memo: MemoBytes?) async throws -> Data {
if let error = createToAddressUskToValueMemoThrowableError {
throw error
}
@ -2276,55 +2276,36 @@ actor ZcashRustBackendWeldingMock: ZcashRustBackendWelding {
}
}
// MARK: - getReceivedMemo
// MARK: - getMemo
var getReceivedMemoIdNoteCallsCount = 0
var getReceivedMemoIdNoteCalled: Bool {
return getReceivedMemoIdNoteCallsCount > 0
var getMemoTxIdOutputIndexThrowableError: Error?
func setGetMemoTxIdOutputIndexThrowableError(_ param: Error?) async {
getMemoTxIdOutputIndexThrowableError = param
}
var getReceivedMemoIdNoteReceivedIdNote: Int64?
var getReceivedMemoIdNoteReturnValue: Memo?
func setGetReceivedMemoIdNoteReturnValue(_ param: Memo?) async {
getReceivedMemoIdNoteReturnValue = param
var getMemoTxIdOutputIndexCallsCount = 0
var getMemoTxIdOutputIndexCalled: Bool {
return getMemoTxIdOutputIndexCallsCount > 0
}
var getReceivedMemoIdNoteClosure: ((Int64) async -> Memo?)?
func setGetReceivedMemoIdNoteClosure(_ param: ((Int64) async -> Memo?)?) async {
getReceivedMemoIdNoteClosure = param
var getMemoTxIdOutputIndexReceivedArguments: (txId: Data, outputIndex: UInt16)?
var getMemoTxIdOutputIndexReturnValue: Memo?
func setGetMemoTxIdOutputIndexReturnValue(_ param: Memo?) async {
getMemoTxIdOutputIndexReturnValue = param
}
var getMemoTxIdOutputIndexClosure: ((Data, UInt16) async throws -> Memo?)?
func setGetMemoTxIdOutputIndexClosure(_ param: ((Data, UInt16) async throws -> Memo?)?) async {
getMemoTxIdOutputIndexClosure = param
}
func getReceivedMemo(idNote: Int64) async -> Memo? {
getReceivedMemoIdNoteCallsCount += 1
getReceivedMemoIdNoteReceivedIdNote = idNote
if let closure = getReceivedMemoIdNoteClosure {
return await closure(idNote)
} else {
return getReceivedMemoIdNoteReturnValue
func getMemo(txId: Data, outputIndex: UInt16) async throws -> Memo? {
if let error = getMemoTxIdOutputIndexThrowableError {
throw error
}
}
// MARK: - getSentMemo
var getSentMemoIdNoteCallsCount = 0
var getSentMemoIdNoteCalled: Bool {
return getSentMemoIdNoteCallsCount > 0
}
var getSentMemoIdNoteReceivedIdNote: Int64?
var getSentMemoIdNoteReturnValue: Memo?
func setGetSentMemoIdNoteReturnValue(_ param: Memo?) async {
getSentMemoIdNoteReturnValue = param
}
var getSentMemoIdNoteClosure: ((Int64) async -> Memo?)?
func setGetSentMemoIdNoteClosure(_ param: ((Int64) async -> Memo?)?) async {
getSentMemoIdNoteClosure = param
}
func getSentMemo(idNote: Int64) async -> Memo? {
getSentMemoIdNoteCallsCount += 1
getSentMemoIdNoteReceivedIdNote = idNote
if let closure = getSentMemoIdNoteClosure {
return await closure(idNote)
getMemoTxIdOutputIndexCallsCount += 1
getMemoTxIdOutputIndexReceivedArguments = (txId: txId, outputIndex: outputIndex)
if let closure = getMemoTxIdOutputIndexClosure {
return try await closure(txId, outputIndex)
} else {
return getSentMemoIdNoteReturnValue
return getMemoTxIdOutputIndexReturnValue
}
}
@ -2685,16 +2666,16 @@ actor ZcashRustBackendWeldingMock: ZcashRustBackendWelding {
return shieldFundsUskMemoShieldingThresholdCallsCount > 0
}
var shieldFundsUskMemoShieldingThresholdReceivedArguments: (usk: UnifiedSpendingKey, memo: MemoBytes?, shieldingThreshold: Zatoshi)?
var shieldFundsUskMemoShieldingThresholdReturnValue: Int64!
func setShieldFundsUskMemoShieldingThresholdReturnValue(_ param: Int64) async {
var shieldFundsUskMemoShieldingThresholdReturnValue: Data!
func setShieldFundsUskMemoShieldingThresholdReturnValue(_ param: Data) async {
shieldFundsUskMemoShieldingThresholdReturnValue = param
}
var shieldFundsUskMemoShieldingThresholdClosure: ((UnifiedSpendingKey, MemoBytes?, Zatoshi) async throws -> Int64)?
func setShieldFundsUskMemoShieldingThresholdClosure(_ param: ((UnifiedSpendingKey, MemoBytes?, Zatoshi) async throws -> Int64)?) async {
var shieldFundsUskMemoShieldingThresholdClosure: ((UnifiedSpendingKey, MemoBytes?, Zatoshi) async throws -> Data)?
func setShieldFundsUskMemoShieldingThresholdClosure(_ param: ((UnifiedSpendingKey, MemoBytes?, Zatoshi) async throws -> Data)?) async {
shieldFundsUskMemoShieldingThresholdClosure = param
}
func shieldFunds(usk: UnifiedSpendingKey, memo: MemoBytes?, shieldingThreshold: Zatoshi) async throws -> Int64 {
func shieldFunds(usk: UnifiedSpendingKey, memo: MemoBytes?, shieldingThreshold: Zatoshi) async throws -> Data {
if let error = shieldFundsUskMemoShieldingThresholdThrowableError {
throw error
}

View File

@ -91,24 +91,19 @@ class RustBackendMockHelper {
await rustBackendMock.setInitBlockMetadataDbClosure() { }
await rustBackendMock.setWriteBlocksMetadataBlocksClosure() { _ in }
await rustBackendMock.setInitAccountsTableUfvksClosure() { _ in }
await rustBackendMock.setCreateToAddressUskToValueMemoReturnValue(-1)
await rustBackendMock.setShieldFundsUskMemoShieldingThresholdReturnValue(-1)
await rustBackendMock.setGetTransparentBalanceAccountReturnValue(0)
await rustBackendMock.setGetVerifiedBalanceAccountReturnValue(0)
await rustBackendMock.setListTransparentReceiversAccountReturnValue([])
await rustBackendMock.setGetCurrentAddressAccountThrowableError(ZcashError.rustGetCurrentAddress("mocked error"))
await rustBackendMock.setGetNextAvailableAddressAccountThrowableError(ZcashError.rustGetNextAvailableAddress("mocked error"))
await rustBackendMock.setShieldFundsUskMemoShieldingThresholdReturnValue(-1)
await rustBackendMock.setCreateAccountSeedThrowableError(ZcashError.rustInitAccountsTableViewingKeyCotainsNullBytes)
await rustBackendMock.setGetReceivedMemoIdNoteReturnValue(nil)
await rustBackendMock.setGetSentMemoIdNoteReturnValue(nil)
await rustBackendMock.setCreateToAddressUskToValueMemoReturnValue(-1)
await rustBackendMock.setGetMemoTxIdOutputIndexReturnValue(nil)
await rustBackendMock.setInitDataDbSeedReturnValue(.seedRequired)
await rustBackendMock.setGetNearestRewindHeightHeightReturnValue(-1)
await rustBackendMock.setInitBlocksTableHeightHashTimeSaplingTreeClosure() { _, _, _, _ in }
await rustBackendMock.setPutUnspentTransparentOutputTxidIndexScriptValueHeightClosure() { _, _, _, _, _ in }
await rustBackendMock.setCreateToAddressUskToValueMemoReturnValue(-1)
await rustBackendMock.setCreateToAddressUskToValueMemoReturnValue(-1)
await rustBackendMock.setCreateToAddressUskToValueMemoThrowableError(ZcashError.rustCreateToAddress("mocked error"))
await rustBackendMock.setShieldFundsUskMemoShieldingThresholdThrowableError(ZcashError.rustShieldFunds("mocked error"))
await rustBackendMock.setDecryptAndStoreTransactionTxBytesMinedHeightThrowableError(ZcashError.rustDecryptAndStoreTransaction("mock fail"))
await rustBackendMock.setInitDataDbSeedClosure() { seed in