ZcashLightClientKit/Sources/ZcashLightClientKit/Rust/ZcashRustBackendWelding.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
}