293 lines
15 KiB
Swift
293 lines
15 KiB
Swift
//
|
|
// ZcashRustBackendWelding.swift
|
|
// ZcashLightClientKit
|
|
//
|
|
// Created by Francisco 'Pacu' Gindre on 2019-12-09.
|
|
// Copyright © 2019 Electric Coin Company. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
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
|
|
case seedNotRelevant
|
|
}
|
|
|
|
// sourcery: mockActor
|
|
protocol ZcashRustBackendWelding {
|
|
/// Returns a list of the accounts in the wallet.
|
|
func listAccounts() async throws -> [Int32]
|
|
|
|
/// 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).
|
|
/// - parameter seed: byte array of the zip32 seed
|
|
/// - parameter treeState: The TreeState Protobuf object for the height prior to the account birthday
|
|
/// - parameter recoverUntil: the fully-scanned height up to which the account will be treated as "being recovered"
|
|
/// - Returns: The `UnifiedSpendingKey` structs for the number of accounts created
|
|
/// - Throws: `rustCreateAccount`.
|
|
func createAccount(seed: [UInt8], treeState: TreeState, recoverUntil: UInt32?) async throws -> UnifiedSpendingKey
|
|
|
|
/// Checks whether the given seed is relevant to any of the derived accounts in the wallet.
|
|
///
|
|
/// - parameter seed: byte array of the seed
|
|
func isSeedRelevantToAnyDerivedAccount(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.
|
|
/// - Throws: `rustDecryptAndStoreTransaction`.
|
|
func decryptAndStoreTransaction(txBytes: [UInt8], minedHeight: Int32) async throws
|
|
|
|
/// Returns the most-recently-generated unified payment address for the specified account.
|
|
/// - parameter account: index of the given account
|
|
/// - Throws:
|
|
/// - `rustGetCurrentAddress` if rust layer returns error.
|
|
/// - `rustGetCurrentAddressInvalidAddress` if generated unified address isn't valid.
|
|
func getCurrentAddress(account: Int32) async 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.
|
|
/// - parameter height: height you would like to rewind to.
|
|
/// - Returns: the blockheight of the nearest rewind height.
|
|
/// - Throws: `rustGetNearestRewindHeight`.
|
|
func getNearestRewindHeight(height: Int32) async throws -> Int32
|
|
|
|
/// Returns a newly-generated unified payment address for the specified account, with the next available diversifier.
|
|
/// - parameter account: index of the given account
|
|
/// - Throws:
|
|
/// - `rustGetNextAvailableAddress` if rust layer returns error.
|
|
/// - `rustGetNextAvailableAddressInvalidAddress` if generated unified address isn't valid.
|
|
func getNextAvailableAddress(account: Int32) async throws -> UnifiedAddress
|
|
|
|
/// 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
|
|
/// - Throws:
|
|
/// - `rustGetTransparentBalanceNegativeAccount` if `account` is < 0.
|
|
/// - `rustGetTransparentBalance` if rust layer returns error.
|
|
func getTransparentBalance(account: Int32) async throws -> Int64
|
|
|
|
/// 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 seed: ZIP-32 compliant seed bytes for this wallet
|
|
/// - 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.
|
|
/// Throws `rustInitDataDb` if rust layer returns error.
|
|
func initDataDb(seed: [UInt8]?) async throws -> DbInitResult
|
|
|
|
/// Returns a list of the transparent receivers for the diversified unified addresses that have
|
|
/// been allocated for the provided account.
|
|
/// - parameter account: index of the given account
|
|
/// - Throws:
|
|
/// - `rustListTransparentReceivers` if rust layer returns error.
|
|
/// - `rustListTransparentReceiversInvalidAddress` if transarent received generated by rust is invalid.
|
|
func listTransparentReceivers(account: Int32) async throws -> [TransparentAddress]
|
|
|
|
/// Get the verified cached transparent balance for the given account
|
|
/// - parameter account: account index to query the balance for.
|
|
/// - Throws:
|
|
/// - `rustGetVerifiedTransparentBalanceNegativeAccount` if `account` is < 0.
|
|
/// - `rustGetVerifiedTransparentBalance` if rust layer returns error.
|
|
func getVerifiedTransparentBalance(account: Int32) async throws -> Int64
|
|
|
|
/// 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
|
|
/// - parameter height: height to rewind to.
|
|
/// - Throws: `rustRewindToHeight` if rust layer returns error.
|
|
func rewindToHeight(height: Int32) async throws
|
|
|
|
/// Resets the state of the FsBlock database to only contain block and transaction information up to the given height.
|
|
/// - Note: this does not delete the files. Only rolls back the database.
|
|
/// - parameter height: height to rewind to. DON'T PASS ARBITRARY HEIGHT. Use `getNearestRewindHeight` when unsure
|
|
/// - Throws: `rustRewindCacheToHeight` if rust layer returns error.
|
|
func rewindCacheToHeight(height: Int32) async throws
|
|
|
|
func putSaplingSubtreeRoots(startIndex: UInt64, roots: [SubtreeRoot]) async throws
|
|
|
|
func putOrchardSubtreeRoots(startIndex: UInt64, roots: [SubtreeRoot]) async throws
|
|
|
|
/// Updates the wallet's view of the blockchain.
|
|
///
|
|
/// This method is used to provide the wallet with information about the state of the blockchain,
|
|
/// and detect any previously scanned data that needs to be re-validated before proceeding with
|
|
/// scanning. It should be called at wallet startup prior to calling `suggestScanRanges`
|
|
/// in order to provide the wallet with the information it needs to correctly prioritize scanning
|
|
/// operations.
|
|
func updateChainTip(height: Int32) async throws
|
|
|
|
/// Returns the height to which the wallet has been fully scanned.
|
|
///
|
|
/// This is the height for which the wallet has fully trial-decrypted this and all
|
|
/// preceding blocks beginning with the wallet's birthday height.
|
|
func fullyScannedHeight() async throws -> BlockHeight?
|
|
|
|
/// Returns the maximum height that the wallet has scanned.
|
|
///
|
|
/// If the wallet is fully synced, this will be equivalent to `fullyScannedHeight`;
|
|
/// otherwise the maximal scanned height is likely to be greater than the fully scanned
|
|
/// height due to the fact that out-of-order scanning can leave gaps.
|
|
func maxScannedHeight() async throws -> BlockHeight?
|
|
|
|
/// Returns the account balances and sync status of the wallet.
|
|
func getWalletSummary() async throws -> WalletSummary?
|
|
|
|
/// Returns a list of suggested scan ranges based upon the current wallet state.
|
|
///
|
|
/// This method should only be used in cases where the `CompactBlock` data that will be
|
|
/// made available to `scanBlocks` for the requested block ranges includes note
|
|
/// commitment tree size information for each block; or else the scan is likely to fail if
|
|
/// notes belonging to the wallet are detected.
|
|
func suggestScanRanges() async throws -> [ScanRange]
|
|
|
|
/// Scans new blocks added to the cache for any transactions received by the tracked
|
|
/// accounts, while checking that they form a valid chan.
|
|
///
|
|
/// This function is built on the core assumption that the information provided in the
|
|
/// block cache 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.
|
|
///
|
|
/// 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.
|
|
///
|
|
/// - 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, fromState: TreeState, limit: UInt32) async throws -> ScanSummary
|
|
|
|
/// Upserts a UTXO into the data db database
|
|
/// - parameter txid: the txid bytes for the UTXO
|
|
/// - parameter index: the index of the UTXO
|
|
/// - parameter script: the script of the UTXO
|
|
/// - parameter value: the value of the UTXO
|
|
/// - parameter height: the mined height for the UTXO
|
|
/// - Throws: `rustPutUnspentTransparentOutput` if rust layer returns error.
|
|
func putUnspentTransparentOutput(
|
|
txid: [UInt8],
|
|
index: Int,
|
|
script: [UInt8],
|
|
value: Int64,
|
|
height: BlockHeight
|
|
) async throws
|
|
|
|
/// Select transaction inputs, compute fees, and construct a proposal for a transaction
|
|
/// that can then be authorized and made ready for submission to the network with
|
|
/// `createProposedTransaction`.
|
|
///
|
|
/// - parameter account: index of the given account
|
|
/// - Parameter to: recipient address
|
|
/// - Parameter value: transaction amount in Zatoshi
|
|
/// - Parameter memo: the `MemoBytes` for this transaction. pass `nil` when sending to transparent receivers
|
|
/// - Throws: `rustCreateToAddress`.
|
|
func proposeTransfer(
|
|
account: Int32,
|
|
to address: String,
|
|
value: Int64,
|
|
memo: MemoBytes?
|
|
) async throws -> FfiProposal
|
|
|
|
/// Select transaction inputs, compute fees, and construct a proposal for a transaction
|
|
/// that can then be authorized and made ready for submission to the network with
|
|
/// `createProposedTransaction` from a valid [ZIP-321](https://zips.z.cash/zip-0321) Payment Request UR
|
|
///
|
|
/// - parameter uri: the URI String that the proposal will be made from.
|
|
/// - parameter account: index of the given account
|
|
/// - Parameter to: recipient address
|
|
/// - Parameter value: transaction amount in Zatoshi
|
|
/// - Parameter memo: the `MemoBytes` for this transaction. pass `nil` when sending to transparent receivers
|
|
/// - Throws: `rustCreateToAddress`.
|
|
func proposeTransferFromURI(
|
|
_ uri: String,
|
|
account: Int32
|
|
) async throws -> FfiProposal
|
|
|
|
/// Constructs a transaction proposal to shield all found UTXOs in data db for the given account,
|
|
/// that can then be authorized and made ready for submission to the network with
|
|
/// `createProposedTransaction`.
|
|
///
|
|
/// Returns the proposal, or `nil` if the transparent balance that would be shielded
|
|
/// is zero or below `shieldingThreshold`.
|
|
///
|
|
/// - parameter account: index of the given account
|
|
/// - Parameter memo: the `Memo` for this transaction
|
|
/// - Parameter transparentReceiver: a specific transparent receiver within the account
|
|
/// that should be the source of transparent funds. Default is `nil` which
|
|
/// will select whichever of the account's transparent receivers has funds
|
|
/// to shield.
|
|
/// - Throws: `rustShieldFunds` if rust layer returns error.
|
|
func proposeShielding(
|
|
account: Int32,
|
|
memo: MemoBytes?,
|
|
shieldingThreshold: Zatoshi,
|
|
transparentReceiver: String?
|
|
) async throws -> FfiProposal?
|
|
|
|
/// Creates a transaction from the given proposal.
|
|
/// - Parameter proposal: the transaction proposal.
|
|
/// - Parameter usk: `UnifiedSpendingKey` for the account that controls the funds to be spent.
|
|
/// - Throws: `rustCreateToAddress`.
|
|
func createProposedTransactions(
|
|
proposal: FfiProposal,
|
|
usk: UnifiedSpendingKey
|
|
) async throws -> [Data]
|
|
|
|
/// Gets the consensus branch id for the given height
|
|
/// - Parameter height: the height you what to know the branch id for
|
|
/// - Throws: `rustNoConsensusBranchId` if rust layer returns error.
|
|
func consensusBranchIdFor(height: Int32) throws -> Int32
|
|
|
|
/// Initializes Filesystem based block cache
|
|
/// - Throws: `rustInitBlockMetadataDb` if rust layer returns error.
|
|
func initBlockMetadataDb() async throws
|
|
|
|
/// Write compact block metadata to a database known to the Rust layer
|
|
/// - Parameter blocks: The `ZcashCompactBlock`s that are going to be marked as stored by the metadata Db.
|
|
/// - Throws:
|
|
/// - `rustWriteBlocksMetadataAllocationProblem` if there problem with allocating memory on Swift side.
|
|
/// - `rustWriteBlocksMetadata` if there is problem with writing blocks metadata.
|
|
func writeBlocksMetadata(blocks: [ZcashCompactBlock]) async throws
|
|
|
|
/// Gets the latest block height stored in the filesystem based cache.
|
|
/// - Parameter fsBlockDbRoot: `URL` pointing to the filesystem root directory where the fsBlock cache is.
|
|
/// this directory is expected to contain a `/blocks` sub-directory with the blocks stored in the convened filename
|
|
/// format `{height}-{hash}-block`. This directory has must be granted both write and read permissions.
|
|
/// - Returns `BlockHeight` of the latest cached block or `.empty` if no blocks are stored.
|
|
func latestCachedBlockHeight() async throws -> BlockHeight
|
|
}
|