487 lines
22 KiB
Swift
487 lines
22 KiB
Swift
//
|
|
// ZcashRustBackendWelding.swift
|
|
// ZcashLightClientKit
|
|
//
|
|
// Created by Francisco Gindre on 12/09/2019.
|
|
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
enum RustWeldingError: Error {
|
|
case genericError(message: String)
|
|
case dataDbInitFailed(message: String)
|
|
case dataDbNotEmpty
|
|
case saplingSpendParametersNotFound
|
|
case malformedStringInput
|
|
case noConsensusBranchId(height: Int32)
|
|
case unableToDeriveKeys
|
|
case getBalanceError(Int, Error)
|
|
case invalidInput(message: String)
|
|
case invalidRewind(suggestedHeight: Int32)
|
|
}
|
|
|
|
enum ZcashRustBackendWeldingConstants {
|
|
static let validChain: Int32 = -1
|
|
}
|
|
/// Enumeration of potential return states for database initialization. If `seedRequired`
|
|
/// is returned, the caller must re-attempt initialization providing the seed
|
|
public enum DbInitResult {
|
|
case success
|
|
case seedRequired
|
|
}
|
|
|
|
protocol ZcashRustBackendWelding {
|
|
/// Adds the next available account-level spend authority, given the current set of [ZIP 316]
|
|
/// account identifiers known, to the wallet database.
|
|
///
|
|
/// Returns the newly created [ZIP 316] account identifier, along with the binary encoding of the
|
|
/// [`UnifiedSpendingKey`] for the newly created account. The caller should manage the memory of
|
|
/// (and store) the returned spending keys in a secure fashion.
|
|
///
|
|
/// If `seed` was imported from a backup and this method is being used to restore a
|
|
/// previous wallet state, you should use this method to add all of the desired
|
|
/// accounts before scanning the chain from the seed's birthday height.
|
|
///
|
|
/// By convention, wallets should only allow a new account to be generated after funds
|
|
/// have been received by the currently-available account (in order to enable
|
|
/// automated account recovery).
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db
|
|
/// - seed: byte array of the zip32 seed
|
|
/// - networkType: network type of this key
|
|
/// - Returns: The `UnifiedSpendingKey` structs for the number of accounts created
|
|
///
|
|
static func createAccount(
|
|
dbData: URL,
|
|
seed: [UInt8],
|
|
networkType: NetworkType
|
|
) throws -> UnifiedSpendingKey
|
|
|
|
/// Creates a transaction to the given address from the given account
|
|
/// - Parameter dbData: URL for the Data DB
|
|
/// - Parameter usk: `UnifiedSpendingKey` for the account that controls the funds to be spent.
|
|
/// - Parameter to: recipient address
|
|
/// - Parameter value: transaction amount in Zatoshi
|
|
/// - Parameter memo: the `MemoBytes` for this transaction. pass `nil` when sending to transparent receivers
|
|
/// - Parameter spendParamsPath: path escaped String for the filesystem locations where the spend parameters are located
|
|
/// - Parameter outputParamsPath: path escaped String for the filesystem locations where the output parameters are located
|
|
/// - Parameter networkType: network type of this key
|
|
static func createToAddress(
|
|
dbData: URL,
|
|
usk: UnifiedSpendingKey,
|
|
to address: String,
|
|
value: Int64,
|
|
memo: MemoBytes?,
|
|
spendParamsPath: String,
|
|
outputParamsPath: String,
|
|
networkType: NetworkType
|
|
) -> Int64 // swiftlint:disable function_parameter_count
|
|
|
|
/// Scans a transaction for any information that can be decrypted by the accounts in the
|
|
/// wallet, and saves it to the wallet.
|
|
///
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db file
|
|
/// - tx: the transaction to decrypt
|
|
/// - minedHeight: height on which this transaction was mined. this is used to fetch the consensus branch ID.
|
|
/// - networkType: network type of this key
|
|
/// returns false if fails to decrypt.
|
|
static func decryptAndStoreTransaction(
|
|
dbData: URL,
|
|
txBytes: [UInt8],
|
|
minedHeight: Int32,
|
|
networkType: NetworkType
|
|
) -> Bool
|
|
|
|
/// Derives and returns a unified spending key from the given seed for the given account ID.
|
|
/// Returns the binary encoding of the spending key. The caller should manage the memory of (and store, if necessary) the returned spending key in a secure fashion.
|
|
/// - Parameter seed: a Byte Array with the seed
|
|
/// - Parameter accountIndex:account index that the key can spend from
|
|
/// - Parameter networkType: network type of this key
|
|
/// - Throws `.unableToDerive` when there's an error
|
|
static func deriveUnifiedSpendingKey(
|
|
from seed: [UInt8],
|
|
accountIndex: Int32,
|
|
networkType: NetworkType
|
|
) throws -> UnifiedSpendingKey
|
|
|
|
/// get the (unverified) balance from the given account
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db
|
|
/// - account: index of the given account
|
|
/// - networkType: network type of this key
|
|
static func getBalance(
|
|
dbData: URL,
|
|
account: Int32,
|
|
networkType: NetworkType
|
|
) throws -> Int64
|
|
|
|
/// Returns the most-recently-generated unified payment address for the specified account.
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db
|
|
/// - account: index of the given account
|
|
/// - networkType: network type of this key
|
|
static func getCurrentAddress(
|
|
dbData: URL,
|
|
account: Int32,
|
|
networkType: NetworkType
|
|
) throws -> UnifiedAddress
|
|
|
|
/// Wallets might need to be rewound because of a reorg, or by user request.
|
|
/// There are times where the wallet could get out of sync for many reasons and
|
|
/// users might be asked to rescan their wallets in order to fix that. This function
|
|
/// returns the nearest height where a rewind is possible. Currently pruning gets rid
|
|
/// of sapling witnesses older than 100 blocks. So in order to reconstruct the witness
|
|
/// tree that allows to spend notes from the given wallet the rewind can't be more than
|
|
/// 100 blocks or back to the oldest unspent note that this wallet contains.
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db file
|
|
/// - height: height you would like to rewind to.
|
|
/// - networkType: network type of this key]
|
|
/// - Returns: the blockheight of the nearest rewind height.
|
|
///
|
|
static func getNearestRewindHeight(
|
|
dbData: URL,
|
|
height: Int32,
|
|
networkType: NetworkType
|
|
) -> Int32
|
|
|
|
/// Returns a newly-generated unified payment address for the specified account, with the next available diversifier.
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db
|
|
/// - account: index of the given account
|
|
/// - networkType: network type of this key
|
|
static func getNextAvailableAddress(
|
|
dbData: URL,
|
|
account: Int32,
|
|
networkType: NetworkType
|
|
) throws -> UnifiedAddress
|
|
|
|
/// get received memo from note
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db file
|
|
/// - idNote: note_id of note where the memo is located
|
|
/// - networkType: network type of this key
|
|
@available(*, deprecated, message: "This function will be deprecated soon. Use `getReceivedMemo(dbData:idNote:networkType)` instead")
|
|
static func getReceivedMemoAsUTF8(
|
|
dbData: URL,
|
|
idNote: Int64,
|
|
networkType: NetworkType
|
|
) -> String?
|
|
|
|
|
|
/// get received memo from note
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db file
|
|
/// - idNote: note_id of note where the memo is located
|
|
/// - networkType: network type of this key
|
|
static func getReceivedMemo(
|
|
dbData: URL,
|
|
idNote: Int64,
|
|
networkType: NetworkType
|
|
) -> Memo?
|
|
|
|
/// Returns the Sapling receiver within the given Unified Address, if any.
|
|
/// - Parameter uAddr: a `UnifiedAddress`
|
|
/// - Returns a `SaplingAddress` if any
|
|
/// - Throws `receiverNotFound` when the receiver is not found. `invalidUnifiedAddress` if the UA provided is not valid
|
|
static func getSaplingReceiver(for uAddr: UnifiedAddress) throws -> SaplingAddress?
|
|
|
|
/// get sent memo from note
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db file
|
|
/// - idNote: note_id of note where the memo is located
|
|
/// - networkType: network type of this key
|
|
@available(*, deprecated, message: "This function will be deprecated soon. Use `getSentMemo(dbData:idNote:networkType)` instead")
|
|
static func getSentMemoAsUTF8(
|
|
dbData: URL,
|
|
idNote: Int64,
|
|
networkType: NetworkType
|
|
) -> String?
|
|
|
|
/// get sent memo from note
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db file
|
|
/// - idNote: note_id of note where the memo is located
|
|
/// - networkType: network type of this key
|
|
/// - Returns: a `Memo` if any
|
|
static func getSentMemo(
|
|
dbData: URL,
|
|
idNote: Int64,
|
|
networkType: NetworkType
|
|
) -> Memo?
|
|
|
|
/// Get the verified cached transparent balance for the given address
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db file
|
|
/// - account; the account index to query
|
|
/// - networkType: network type of this key
|
|
static func getTransparentBalance(
|
|
dbData: URL,
|
|
account: Int32,
|
|
networkType: NetworkType
|
|
) throws -> Int64
|
|
|
|
/// Returns the transparent receiver within the given Unified Address, if any.
|
|
// - Parameter uAddr: a `UnifiedAddress`
|
|
/// - Returns a `TransparentAddress` if any
|
|
/// - Throws `receiverNotFound` when the receiver is not found. `invalidUnifiedAddress` if the UA provided is not valid
|
|
static func getTransparentReceiver(for uAddr: UnifiedAddress) throws -> TransparentAddress?
|
|
|
|
/// gets the latest error if available. Clear the existing error
|
|
/// - Returns a `RustWeldingError` if exists
|
|
static func lastError() -> RustWeldingError?
|
|
|
|
/// gets the latest error message from librustzcash. Does not clear existing error
|
|
static func getLastError() -> String?
|
|
|
|
/// initialize the accounts table from a set of unified full viewing keys
|
|
/// - Note: this function should only be used when restoring an existing seed phrase.
|
|
/// when creating a new wallet, use `createAccount()` instead
|
|
/// - Parameter dbData: location of the data db
|
|
/// - Parameter ufvks: an array of UnifiedFullViewingKeys
|
|
/// - Parameter networkType: network type of this key
|
|
static func initAccountsTable(
|
|
dbData: URL,
|
|
ufvks: [UnifiedFullViewingKey],
|
|
networkType: NetworkType
|
|
) throws
|
|
|
|
/// initializes the data db. This will performs any migrations needed on the sqlite file
|
|
/// provided. Some migrations might need that callers provide the seed bytes.
|
|
/// - Parameter dbData: location of the data db sql file
|
|
/// - Parameter seed: ZIP-32 compliant seed bytes for this wallet
|
|
/// - Parameter networkType: network type of this key
|
|
/// - Returns: `DbInitResult.success` if the dataDb was initialized successfully
|
|
/// or `DbInitResult.seedRequired` if the operation requires the seed to be passed
|
|
/// in order to be completed successfully.
|
|
static func initDataDb(
|
|
dbData: URL,
|
|
seed: [UInt8]?,
|
|
networkType: NetworkType
|
|
) throws -> DbInitResult
|
|
|
|
/// Returns the network and address type for the given Zcash address string,
|
|
/// if the string represents a valid Zcash address.
|
|
static func getAddressMetadata(_ address: String) -> AddressMetadata?
|
|
|
|
/// Validates the if the given string is a valid Sapling Address
|
|
/// - Parameter address: UTF-8 encoded String to validate
|
|
/// - Parameter networkType: network type of this key
|
|
/// - Returns: true when the address is valid. Returns false in any other case
|
|
/// - Throws: Error when the provided address belongs to another network
|
|
static func isValidSaplingAddress(_ address: String, networkType: NetworkType) -> Bool
|
|
|
|
/// Validates the if the given string is a valid Sapling Extended Full Viewing Key
|
|
/// - Parameter key: UTF-8 encoded String to validate
|
|
/// - Parameter networkType: network type of this key
|
|
/// - Returns: `true` when the Sapling Extended Full Viewing Key is valid. `false` in any other case
|
|
/// - Throws: Error when there's another problem not related to validity of the string in question
|
|
static func isValidSaplingExtendedFullViewingKey(_ key: String, networkType: NetworkType) -> Bool
|
|
|
|
/// Validates the if the given string is a valid Sapling Extended Spending Key
|
|
/// - Returns: `true` when the Sapling Extended Spending Key is valid, false in any other case.
|
|
/// - Throws: Error when the key is semantically valid but it belongs to another network
|
|
/// - parameter key: String encoded Extended Spending Key
|
|
/// - parameter networkType: `NetworkType` signaling testnet or mainnet
|
|
static func isValidSaplingExtendedSpendingKey(_ key: String, networkType: NetworkType) -> Bool
|
|
|
|
/// Validates the if the given string is a valid Transparent Address
|
|
/// - Parameter address: UTF-8 encoded String to validate
|
|
/// - Parameter networkType: network type of this key
|
|
/// - Returns: true when the address is valid and transparent. false in any other case
|
|
/// - Throws: Error when the provided address belongs to another network
|
|
static func isValidTransparentAddress(_ address: String, networkType: NetworkType) -> Bool
|
|
|
|
/// validates whether a string encoded address is a valid Unified Address.
|
|
/// - Parameter address: UTF-8 encoded String to validate
|
|
/// - Parameter networkType: network type of this key
|
|
/// - Returns: true when the address is valid and transparent. false in any other case
|
|
/// - Throws: Error when the provided address belongs to another network
|
|
static func isValidUnifiedAddress(_ address: String, networkType: NetworkType) -> Bool
|
|
|
|
/// verifies that the given string-encoded `UnifiedFullViewingKey` is valid.
|
|
/// - Parameter ufvk: UTF-8 encoded String to validate
|
|
/// - Parameter networkType: network type of this key
|
|
/// - Returns: true when the encoded string is a valid UFVK. false in any other case
|
|
/// - Throws: Error when there's another problem not related to validity of the string in question
|
|
static func isValidUnifiedFullViewingKey(_ ufvk: String, networkType: NetworkType) -> Bool
|
|
|
|
/// initialize the blocks table from a given checkpoint (height, hash, time, saplingTree and networkType)
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db
|
|
/// - height: represents the block height of the given checkpoint
|
|
/// - hash: hash of the merkle tree
|
|
/// - time: in milliseconds from reference
|
|
/// - saplingTree: hash of the sapling tree
|
|
/// - networkType: `NetworkType` signaling testnet or mainnet
|
|
static func initBlocksTable(
|
|
dbData: URL,
|
|
height: Int32,
|
|
hash: String,
|
|
time: UInt32,
|
|
saplingTree: String,
|
|
networkType: NetworkType
|
|
) throws // swiftlint:disable function_parameter_count
|
|
|
|
/// Returns a list of the transparent receivers for the diversified unified addresses that have
|
|
/// been allocated for the provided account.
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db
|
|
/// - account: index of the given account
|
|
/// - networkType: the network type
|
|
static func listTransparentReceivers(
|
|
dbData: URL,
|
|
account: Int32,
|
|
networkType: NetworkType
|
|
) throws -> [TransparentAddress]
|
|
|
|
/// get the verified balance from the given account
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db
|
|
/// - account: index of the given account
|
|
/// - networkType: the network type
|
|
static func getVerifiedBalance(
|
|
dbData: URL,
|
|
account: Int32,
|
|
networkType: NetworkType
|
|
) throws -> Int64
|
|
|
|
|
|
/// Get the verified cached transparent balance for the given account
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db
|
|
/// - account: account index to query the balance for.
|
|
/// - networkType: the network type
|
|
static func getVerifiedTransparentBalance(
|
|
dbData: URL,
|
|
account: Int32,
|
|
networkType: NetworkType
|
|
) throws -> Int64
|
|
|
|
/// Checks that the scanned blocks in the data database, when combined with the recent
|
|
/// `CompactBlock`s in the cache database, form a valid chain.
|
|
/// This function is built on the core assumption that the information provided in the
|
|
/// cache database is more likely to be accurate than the previously-scanned information.
|
|
/// This follows from the design (and trust) assumption that the `lightwalletd` server
|
|
/// provides accurate block information as of the time it was requested.
|
|
/// - Parameters:
|
|
/// - dbCache: location of the cache db file
|
|
/// - dbData: location of the data db file
|
|
/// - networkType: the network type
|
|
/// - Returns:
|
|
/// - `-1` if the combined chain is valid.
|
|
/// - `upper_bound` if the combined chain is invalid.
|
|
/// - `upper_bound` is the height of the highest invalid block (on the assumption that the highest block in the cache database is correct).
|
|
/// - `0` if there was an error during validation unrelated to chain validity.
|
|
/// - Important: This function does not mutate either of the databases.
|
|
static func validateCombinedChain(
|
|
dbCache: URL,
|
|
dbData: URL,
|
|
networkType: NetworkType
|
|
) -> Int32
|
|
|
|
/// Resets the state of the database to only contain block and transaction information up to the given height. clears up all derived data as well
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db file
|
|
/// - height: height to rewind to. DON'T PASS ARBITRARY HEIGHT. Use getNearestRewindHeight when unsure
|
|
/// - networkType: the network type
|
|
static func rewindToHeight(
|
|
dbData: URL,
|
|
height: Int32,
|
|
networkType: NetworkType
|
|
) -> Bool
|
|
|
|
|
|
/// Scans new blocks added to the cache for any transactions received by the tracked
|
|
/// accounts.
|
|
/// This function pays attention only to cached blocks with heights greater than the
|
|
/// highest scanned block in `db_data`. Cached blocks with lower heights are not verified
|
|
/// against previously-scanned blocks. In particular, this function **assumes** that the
|
|
/// caller is handling rollbacks.
|
|
/// For brand-new light client databases, this function starts scanning from the Sapling
|
|
/// activation height. This height can be fast-forwarded to a more recent block by calling
|
|
/// [`initBlocksTable`] before this function.
|
|
/// Scanned blocks are required to be height-sequential. If a block is missing from the
|
|
/// cache, an error will be signalled.
|
|
///
|
|
/// - Parameters:
|
|
/// - dbCache: location of the compact block cache db
|
|
/// - dbData: location of the data db file
|
|
/// - limit: scan up to limit blocks. pass 0 to set no limit.
|
|
/// - networkType: the network type
|
|
/// returns false if fails to scan.
|
|
static func scanBlocks(
|
|
dbCache: URL,
|
|
dbData: URL,
|
|
limit: UInt32,
|
|
networkType: NetworkType
|
|
) -> Bool
|
|
|
|
|
|
/// puts a UTXO into the data db database
|
|
/// - Parameters:
|
|
/// - dbData: location of the data db file
|
|
/// - txid: the txid bytes for the UTXO
|
|
/// - index: the index of the UTXO
|
|
/// - script: the script of the UTXO
|
|
/// - value: the value of the UTXO
|
|
/// - height: the mined height for the UTXO
|
|
/// - networkType: the network type
|
|
/// - Returns: true if the operation succeeded or false otherwise
|
|
static func putUnspentTransparentOutput(
|
|
dbData: URL,
|
|
txid: [UInt8],
|
|
index: Int,
|
|
script: [UInt8],
|
|
value: Int64,
|
|
height: BlockHeight,
|
|
networkType: NetworkType
|
|
) throws -> Bool
|
|
|
|
/// Creates a transaction to shield all found UTXOs in cache db for the account the provided `UnifiedSpendingKey` has spend authority for.
|
|
/// - Parameter dbCache: URL for the Cache DB
|
|
/// - Parameter dbData: URL for the Data DB
|
|
/// - Parameter usk: `UnifiedSpendingKey` that spend transparent funds and where the funds will be shielded to.
|
|
/// - Parameter memo: the `Memo` for this transaction
|
|
/// - Parameter spendParamsPath: path escaped String for the filesystem locations where the spend parameters are located
|
|
/// - Parameter outputParamsPath: path escaped String for the filesystem locations where the output parameters are located
|
|
/// - Parameter networkType: the network type
|
|
static func shieldFunds(
|
|
dbCache: URL,
|
|
dbData: URL,
|
|
usk: UnifiedSpendingKey,
|
|
memo: MemoBytes?,
|
|
spendParamsPath: String,
|
|
outputParamsPath: String,
|
|
networkType: NetworkType
|
|
) -> Int64 // swiftlint:disable function_parameter_count
|
|
|
|
/// Obtains the available receiver typecodes for the given String encoded Unified Address
|
|
/// - Parameter address: public key represented as a String
|
|
/// - Returns the `[UInt32]` that compose the given UA
|
|
/// - Throws `RustWeldingError.invalidInput(message: String)` when the UA is either invalid or malformed
|
|
static func receiverTypecodesOnUnifiedAddress(_ address: String) throws -> [UInt32]
|
|
|
|
|
|
/// Gets the consensus branch id for the given height
|
|
/// - Parameter height: the height you what to know the branch id for
|
|
/// - Parameter networkType: the network type
|
|
static func consensusBranchIdFor(
|
|
height: Int32,
|
|
networkType: NetworkType
|
|
) throws -> Int32
|
|
|
|
|
|
/// Derives a `UnifiedFullViewingKey` from a `UnifiedSpendingKey`
|
|
/// - Parameter spendingKey: the `UnifiedSpendingKey` to derive from
|
|
/// - Parameter networkType: the network type
|
|
/// - Throws: `RustWeldingError.unableToDeriveKeys` if the SDK couldn't derive the UFVK.
|
|
/// - Returns: the derived `UnifiedFullViewingKey`
|
|
static func deriveUnifiedFullViewingKey(
|
|
from spendingKey: UnifiedSpendingKey,
|
|
networkType: NetworkType
|
|
) throws -> UnifiedFullViewingKey
|
|
}
|