Compare commits

...

19 Commits

Author SHA1 Message Date
Pacu 5817f6926d
Merge 09d220593f into d8f389b8da 2024-03-27 20:12:52 -03:00
Lukas Korba d8f389b8da
Merge pull request #1405 from LukasKorba/1404-Release-2-1-2
[#1404] Release 2.1.2
2024-03-27 23:22:31 +01:00
Lukas Korba eb2ebeaf97 [#1404] Release 2.1.2
- fix for a bug in note selection when sending to a transparent recipient
2024-03-27 23:18:57 +01:00
Lukas Korba 279de9a2a4
Merge pull request #1403 from LukasKorba/1402-Release-2-1-1
[#1402] Release 2.1.1
2024-03-27 16:48:46 +01:00
Lukas Korba e3cb722db8 [#1402] Release 2.1.1
- FFI bump

[#1402] Release 2.1.1

- changelog updated
2024-03-27 16:47:24 +01:00
Lukas Korba 8909f23722
Merge pull request #1400 from LukasKorba/1398-Release-2-1-0
[#1398] Release 2.1.0
2024-03-26 18:15:30 +01:00
Lukas Korba c5e07943d3 [#1398] Release 2.1.0
- changelog updated for the release
2024-03-26 18:03:01 +01:00
Lukas Korba b183b10d13
Merge pull request #1393 from Electric-Coin-Company/feature-2.1.0
Feature branch for SDK 2.1.0
2024-03-26 18:00:38 +01:00
Lukas Korba c3e6201bcd
Merge pull request #1397 from Electric-Coin-Company/orchard-fixes
Orchard implementation fixes
2024-03-26 17:54:02 +01:00
Lukas Korba 4a1edd7e44
Merge pull request #1399 from LukasKorba/checkpoints-update
checkpoints-update
2024-03-26 17:53:33 +01:00
Lukas Korba 41cf1357bd checkpoints-update
- checkpoints added
2024-03-26 17:51:24 +01:00
Jack Grigg fa4def9f29 Add missing `ZcashTransaction.Output.Pool.orchard` case 2024-03-26 08:24:00 -04:00
Jack Grigg 43534d26d9 Integrate Orchard support and latest Rust updates 2024-03-25 23:19:44 -04:00
str4d 730aee0c5f
Merge pull request #1395 from LukasKorba/public-isSeedRelevantToWallet
Public API isSeedRelevantToWallet
2024-03-18 14:35:19 +00:00
Lukas Korba e1c600b8ff Public API isSeedRelevantToWallet
- New public API `isSeedRelevantToWallet` has been implemented
- 2 swiftlint error have been resolved
- Mocks generated
2024-03-18 14:45:30 +01:00
Jack Grigg a5a0ef0ac1 Migrate to latest in-progress revision of Rust crates
- New backend method `ZcashRustBackend.isSeedRelevantToWallet`
- `ZcashRustBackend.scanBlocks` now takes a `fromState` argument.

Co-authored-by: Lukas Korba <lukas.korba@seznam.cz>
2024-03-15 16:01:39 +00:00
Jack Grigg 86defc8b4a Remove `AccountRepository`
This removes the last direct access to the `accounts` table; all access
now goes through the Rust FFI.
2024-03-15 15:26:44 +00:00
Jack Grigg dd9942b6ab Remove `UnspentTransactionOutputRepository`
This removes the last direct access to the `utxos` table; all access
now goes through the Rust FFI.

`SDKSynchronizer.latestUTXOs` is removed without replacement. It was
introduced during the initial addition of shielding support, but:

- It is no longer used anywhere inside the SDK (when added, it was
  used in a few other methods).
- It is not exposed in the `Synchronizer` protocol.
- It is AFAICT unused in Zashi iOS, Edge, and Unstoppable.
- It was functionally replaced by `refreshUTXOs`, which performs
  best-effort UTXO updates instead of failing on any error. (It also
  does not clear the `utxo`s table which makes it not equivalent.)
2024-03-15 14:37:17 +00:00
Francisco Gindre 09d220593f
[#1330] Ability to provide custom checkpoints on Testing environments
Closes #1330
Closes #1314

This implements a CheckpointSource that returns the checkpoint for height 663150
used on darksidewalletd tests.

also makes CheckpointSourceFactory an Enum so it can be initialized as
value
2024-03-14 14:35:17 -03:00
58 changed files with 575 additions and 473 deletions

View File

@ -5,6 +5,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this library adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
# Unreleased
# 2.1.2 - 2024-03-27
## Fixed
- Bug in note selection when sending to a transparent recipient.
# 2.1.1 - 2024-03-27
## Fixed
- Bug in an SQL query that prevented shielding of transparent funds.
# 2.1.0 - 2024-03-26
### [#1379] Fulfill Payment from a valid ZIP-321 request
New API implemented that allows clients to use a ZIP-321 Payment URI to create transaction.
```
@ -18,6 +31,29 @@ Possible errors:
- `ZcashError.rustProposeTransferFromURI`
- Other errors that `sentToAddress` can throw
## Removed
- `SDKSynchronizer.latestUTXOs`
## Checkpoints
Mainnet
````
Sources/ZcashLightClientKit/Resources/checkpoints/mainnet/2430000.json
...
Sources/ZcashLightClientKit/Resources/checkpoints/mainnet/2447500.json
````
Testnet
````
Sources/ZcashLightClientKit/Resources/checkpoints/testnet/2750000.json
...
Sources/ZcashLightClientKit/Resources/checkpoints/testnet/2770000.json
````
# 2.0.11 - 2024-03-08
## Changed

View File

@ -176,8 +176,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/zcash-hackworks/zcash-light-client-ffi",
"state" : {
"revision" : "7c801be1f445402a433b32835a50d832e8a50437",
"version" : "0.6.0"
"revision" : "8838b4f0ee4193349fed09f0248220d4ada271fc",
"version" : "0.7.3"
}
}
],

View File

@ -122,8 +122,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/zcash-hackworks/zcash-light-client-ffi",
"state" : {
"revision" : "7c801be1f445402a433b32835a50d832e8a50437",
"version" : "0.6.0"
"revision" : "c7e5158edf5e62af15492d30237163b78af35ce9",
"version" : "0.7.1"
}
}
],

View File

@ -16,7 +16,7 @@ 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")
.package(url: "https://github.com/zcash-hackworks/zcash-light-client-ffi", exact: "0.7.3")
],
targets: [
.target(

View File

@ -28,7 +28,6 @@ actor CompactBlockProcessor {
private let configProvider: ConfigProvider
private var afterSyncHooksManager = AfterSyncHooksManager()
private let accountRepository: AccountRepository
var blockDownloaderService: BlockDownloaderService
private var latestBlocksDataProvider: LatestBlocksDataProvider
private let logger: Logger
@ -142,20 +141,6 @@ actor CompactBlockProcessor {
}
}
/// Initializes a CompactBlockProcessor instance
/// - Parameters:
/// - service: concrete implementation of `LightWalletService` protocol
/// - storage: concrete implementation of `CompactBlockRepository` protocol
/// - backend: a class that complies to `ZcashRustBackendWelding`
/// - config: `Configuration` struct for this processor
init(container: DIContainer, config: Configuration) {
self.init(
container: container,
config: config,
accountRepository: AccountRepositoryBuilder.build(dataDbURL: config.dataDb, readOnly: true, logger: container.resolve(Logger.self))
)
}
/// Initializes a CompactBlockProcessor instance from an Initialized object
/// - Parameters:
/// - initializer: an instance that complies to CompactBlockDownloading protocol
@ -171,20 +156,23 @@ actor CompactBlockProcessor {
saplingParamsSourceURL: initializer.saplingParamsSourceURL,
walletBirthdayProvider: walletBirthdayProvider,
network: initializer.network
),
accountRepository: initializer.accountRepository
)
)
}
/// Initializes a CompactBlockProcessor instance
/// - Parameters:
/// - service: concrete implementation of `LightWalletService` protocol
/// - storage: concrete implementation of `CompactBlockRepository` protocol
/// - backend: a class that complies to `ZcashRustBackendWelding`
/// - config: `Configuration` struct for this processor
init(
container: DIContainer,
config: Configuration,
accountRepository: AccountRepository
config: Configuration
) {
Dependencies.setupCompactBlockProcessor(
in: container,
config: config,
accountRepository: accountRepository
config: config
)
let configProvider = ConfigProvider(config: config)
@ -200,7 +188,6 @@ actor CompactBlockProcessor {
self.storage = container.resolve(CompactBlockRepository.self)
self.config = config
self.transactionRepository = container.resolve(TransactionRepository.self)
self.accountRepository = accountRepository
self.fileManager = container.resolve(ZcashFileManager.self)
self.configProvider = configProvider
}

View File

@ -23,7 +23,6 @@ protocol UTXOFetcher {
}
struct UTXOFetcherImpl {
let accountRepository: AccountRepository
let blockDownloaderService: BlockDownloaderService
let config: UTXOFetcherConfig
let rustBackend: ZcashRustBackendWelding
@ -37,8 +36,7 @@ extension UTXOFetcherImpl: UTXOFetcher {
) async throws -> (inserted: [UnspentTransactionOutputEntity], skipped: [UnspentTransactionOutputEntity]) {
try Task.checkCancellation()
let accounts = try accountRepository.getAll()
.map { $0.account }
let accounts = try await rustBackend.listAccounts()
var tAddresses: [TransparentAddress] = []
for account in accounts {

View File

@ -23,6 +23,7 @@ protocol BlockScanner {
struct BlockScannerImpl {
let config: BlockScannerConfig
let rustBackend: ZcashRustBackendWelding
let service: LightWalletService
let transactionRepository: TransactionRepository
let metrics: SDKMetrics
let logger: Logger
@ -56,7 +57,9 @@ extension BlockScannerImpl: BlockScanner {
let scanSummary: ScanSummary
let scanStartTime = Date()
do {
scanSummary = try await self.rustBackend.scanBlocks(fromHeight: Int32(startHeight), limit: batchSize)
let fromState = try await service.getTreeState(BlockID(height: startHeight - 1))
scanSummary = try await self.rustBackend.scanBlocks(fromHeight: Int32(startHeight), fromState: fromState, limit: batchSize)
} catch {
logger.debug("block scanning failed with error: \(String(describing: error))")
throw error

View File

@ -7,7 +7,7 @@
import Foundation
struct CheckpointSourceFactory {
enum CheckpointSourceFactory {
static func fromBundle(for network: NetworkType) -> CheckpointSource {
BundleCheckpointSource(network: network)
}

View File

@ -8,25 +8,12 @@
import Foundation
struct UTXO: Decodable, Encodable {
enum CodingKeys: String, CodingKey {
case id = "id_utxo"
case address
case prevoutTxId = "prevout_txid"
case prevoutIndex = "prevout_idx"
case script
case valueZat = "value_zat"
case height
case spentInTx = "spent_in_tx"
}
let id: Int?
let address: String
var prevoutTxId: Data
var prevoutIndex: Int
let script: Data
let valueZat: Int
let height: Int
let spentInTx: Int?
}
extension UTXO: UnspentTransactionOutputEntity {
@ -48,145 +35,3 @@ extension UTXO: UnspentTransactionOutputEntity {
}
}
}
extension UnspentTransactionOutputEntity {
/**
As UTXO, with id and spentIntTx set to __nil__
*/
func asUTXO() -> UTXO {
UTXO(
id: nil,
address: address,
prevoutTxId: txid,
prevoutIndex: index,
script: script,
valueZat: valueZat,
height: height,
spentInTx: nil
)
}
}
import SQLite
class UnspentTransactionOutputSQLDAO: UnspentTransactionOutputRepository {
enum TableColumns {
static let id = Expression<Int>("id_utxo")
static let address = Expression<String>("address")
static let txid = Expression<Blob>("prevout_txid")
static let index = Expression<Int>("prevout_idx")
static let script = Expression<Blob>("script")
static let valueZat = Expression<Int>("value_zat")
static let height = Expression<Int>("height")
static let spentInTx = Expression<Int?>("spent_in_tx")
}
let table = Table("utxos")
let dbProvider: ConnectionProvider
init(dbProvider: ConnectionProvider) {
self.dbProvider = dbProvider
}
/// - Throws: `unspentTransactionOutputDAOCreateTable` if creation table fails.
func initialise() async throws {
try await createTableIfNeeded()
}
private func createTableIfNeeded() async throws {
let stringStatement =
"""
CREATE TABLE IF NOT EXISTS utxos (
id_utxo INTEGER PRIMARY KEY,
address TEXT NOT NULL,
prevout_txid BLOB NOT NULL,
prevout_idx INTEGER NOT NULL,
script BLOB NOT NULL,
value_zat INTEGER NOT NULL,
height INTEGER NOT NULL,
spent_in_tx INTEGER,
FOREIGN KEY (spent_in_tx) REFERENCES transactions(id_tx),
CONSTRAINT tx_outpoint UNIQUE (prevout_txid, prevout_idx)
)
"""
do {
globalDBLock.lock()
defer { globalDBLock.unlock() }
try dbProvider.connection().run(stringStatement)
} catch {
throw ZcashError.unspentTransactionOutputDAOCreateTable(error)
}
}
/// - Throws: `unspentTransactionOutputDAOStore` if sqlite query fails.
func store(utxos: [UnspentTransactionOutputEntity]) async throws {
do {
globalDBLock.lock()
defer { globalDBLock.unlock() }
let db = try dbProvider.connection()
try db.transaction {
for utxo in utxos.map({ $0 as? UTXO ?? $0.asUTXO() }) {
try db.run(table.insert(utxo))
}
}
} catch {
throw ZcashError.unspentTransactionOutputDAOStore(error)
}
}
/// - Throws: `unspentTransactionOutputDAOClearAll` if sqlite query fails.
func clearAll(address: String?) async throws {
do {
globalDBLock.lock()
defer { globalDBLock.unlock() }
if let tAddr = address {
try dbProvider.connection().run(table.filter(TableColumns.address == tAddr).delete())
} else {
try dbProvider.connection().run(table.delete())
}
} catch {
throw ZcashError.unspentTransactionOutputDAOClearAll(error)
}
}
/// - Throws:
/// - `unspentTransactionOutputDAOClearAll` if the data fetched from the DB can't be decoded to `UTXO` object.
/// - `unspentTransactionOutputDAOGetAll` if sqlite query fails.
func getAll(address: String?) async throws -> [UnspentTransactionOutputEntity] {
do {
if let tAddress = address {
let allTxs: [UTXO] = try dbProvider.connection()
.prepare(table.filter(TableColumns.address == tAddress))
.map { row in
do {
return try row.decode()
} catch {
throw ZcashError.unspentTransactionOutputDAOGetAllCantDecode(error)
}
}
return allTxs
} else {
let allTxs: [UTXO] = try dbProvider.connection()
.prepare(table)
.map { row in
try row.decode()
}
return allTxs
}
} catch {
if let error = error as? ZcashError {
throw error
} else {
throw ZcashError.unspentTransactionOutputDAOGetAll(error)
}
}
}
}
enum UTXORepositoryBuilder {
static func build(initializer: Initializer) -> UnspentTransactionOutputRepository {
return UnspentTransactionOutputSQLDAO(dbProvider: SimpleConnectionProvider(path: initializer.dataDbURL.path))
}
}

View File

@ -14,11 +14,6 @@ protocol AccountEntity {
}
struct DbAccount: AccountEntity, Encodable, Decodable {
enum CodingKeys: String, CodingKey {
case account
case ufvk
}
let account: Int
let ufvk: String
}
@ -38,171 +33,3 @@ extension DbAccount: Hashable {
return true
}
}
protocol AccountRepository {
func getAll() throws -> [AccountEntity]
func findBy(account: Int) throws -> AccountEntity?
func update(_ account: AccountEntity) throws
}
class AccountSQDAO: AccountRepository {
enum TableColums {
static let account = Expression<Int>("account")
static let extfvk = Expression<String>("ufvk")
}
let table = Table("accounts")
let dbProvider: ConnectionProvider
let logger: Logger
init(dbProvider: ConnectionProvider, logger: Logger) {
self.dbProvider = dbProvider
self.logger = logger
}
/// - Throws:
/// - `accountDAOGetAllCantDecode` if account data fetched from the db can't be decoded to the `Account` object.
/// - `accountDAOGetAll` if sqlite query fetching account data failed.
func getAll() throws -> [AccountEntity] {
do {
globalDBLock.lock()
defer { globalDBLock.unlock() }
return try dbProvider.connection()
.prepare(table)
.map { row -> DbAccount in
do {
return try row.decode()
} catch {
throw ZcashError.accountDAOGetAllCantDecode(error)
}
}
} catch {
if let error = error as? ZcashError {
throw error
} else {
throw ZcashError.accountDAOGetAll(error)
}
}
}
/// - Throws:
/// - `accountDAOFindByCantDecode` if account data fetched from the db can't be decoded to the `Account` object.
/// - `accountDAOFindBy` if sqlite query fetching account data failed.
func findBy(account: Int) throws -> AccountEntity? {
let query = table.filter(TableColums.account == account).limit(1)
do {
globalDBLock.lock()
defer { globalDBLock.unlock() }
return try dbProvider.connection()
.prepare(query)
.map {
do {
return try $0.decode() as DbAccount
} catch {
throw ZcashError.accountDAOFindByCantDecode(error)
}
}
.first
} catch {
if let error = error as? ZcashError {
throw error
} else {
throw ZcashError.accountDAOFindBy(error)
}
}
}
/// - Throws:
/// - `accountDAOUpdate` if sqlite query updating account failed.
/// - `accountDAOUpdatedZeroRows` if sqlite query updating account pass but it affects 0 rows.
func update(_ account: AccountEntity) throws {
guard let acc = account as? DbAccount else {
throw ZcashError.accountDAOUpdateInvalidAccount
}
let updatedRows: Int
do {
globalDBLock.lock()
defer { globalDBLock.unlock() }
updatedRows = try dbProvider.connection().run(table.filter(TableColums.account == acc.account).update(acc))
} catch {
throw ZcashError.accountDAOUpdate(error)
}
if updatedRows == 0 {
logger.error("attempted to update pending transactions but no rows were updated")
throw ZcashError.accountDAOUpdatedZeroRows
}
}
}
class CachingAccountDao: AccountRepository {
let dao: AccountRepository
lazy var cache: [Int: AccountEntity] = {
var accountCache: [Int: AccountEntity] = [:]
guard let all = try? dao.getAll() else {
return accountCache
}
for acc in all {
accountCache[acc.account] = acc
}
return accountCache
}()
init(dao: AccountRepository) {
self.dao = dao
}
func getAll() throws -> [AccountEntity] {
guard cache.isEmpty else {
return cache.values.sorted(by: { $0.account < $1.account })
}
let all = try dao.getAll()
for acc in all {
cache[acc.account] = acc
}
return all
}
func findBy(account: Int) throws -> AccountEntity? {
if let acc = cache[account] {
return acc
}
let acc = try dao.findBy(account: account)
cache[account] = acc
return acc
}
func update(_ account: AccountEntity) throws {
try dao.update(account)
}
}
enum AccountRepositoryBuilder {
static func build(dataDbURL: URL, readOnly: Bool = false, caching: Bool = false, logger: Logger) -> AccountRepository {
if caching {
return CachingAccountDao(
dao: AccountSQDAO(
dbProvider: SimpleConnectionProvider(path: dataDbURL.path, readonly: readOnly),
logger: logger
)
)
} else {
return AccountSQDAO(
dbProvider: SimpleConnectionProvider(path: dataDbURL.path, readonly: readOnly),
logger: logger
)
}
}
}

View File

@ -65,6 +65,7 @@ public enum ZcashTransaction {
public enum Pool {
case transaparent
case sapling
case orchard
case other(Int)
init(rawValue: Int) {
switch rawValue {
@ -72,6 +73,8 @@ public enum ZcashTransaction {
self = .transaparent
case 2:
self = .sapling
case 3:
self = .orchard
default:
self = .other(rawValue)
}
@ -101,8 +104,8 @@ extension ZcashTransaction.Output {
static let rawID = Expression<Blob>("txid")
static let pool = Expression<Int>("output_pool")
static let index = Expression<Int>("output_index")
static let toAccount = Expression<Int?>("to_account")
static let fromAccount = Expression<Int?>("from_account")
static let toAccount = Expression<Int?>("to_account_id")
static let fromAccount = Expression<Int?>("from_account_id")
static let toAddress = Expression<String?>("to_address")
static let value = Expression<Int64>("value")
static let isChange = Expression<Bool>("is_change")

View File

@ -325,6 +325,14 @@ public enum ZcashError: Equatable, Error {
/// - `rustError` contains error generated by the rust layer.
/// ZRUST0057
case rustProposeTransferFromURI(_ rustError: String)
/// Error from rust layer when calling ZcashRustBackend.
/// - `rustError` contains error generated by the rust layer.
/// ZRUST0058
case rustListAccounts(_ rustError: String)
/// Error from rust layer when calling ZcashRustBackend.rustIsSeedRelevantToAnyDerivedAccount
/// - `rustError` contains error generated by the rust layer.
/// ZRUST0059
case rustIsSeedRelevantToAnyDerivedAccount(_ rustError: String)
/// SQLite query failed when fetching all accounts from the database.
/// - `sqliteError` is error produced by SQLite library.
/// ZADAO0001
@ -681,6 +689,8 @@ public enum ZcashError: Equatable, Error {
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 .rustProposeTransferFromURI: return "Error from rust layer when calling ZcashRustBackend."
case .rustListAccounts: return "Error from rust layer when calling ZcashRustBackend."
case .rustIsSeedRelevantToAnyDerivedAccount: return "Error from rust layer when calling ZcashRustBackend.rustIsSeedRelevantToAnyDerivedAccount"
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."
@ -856,6 +866,8 @@ public enum ZcashError: Equatable, Error {
case .rustScanProgressOutOfRange: return .rustScanProgressOutOfRange
case .rustGetWalletSummary: return .rustGetWalletSummary
case .rustProposeTransferFromURI: return .rustProposeTransferFromURI
case .rustListAccounts: return .rustListAccounts
case .rustIsSeedRelevantToAnyDerivedAccount: return .rustIsSeedRelevantToAnyDerivedAccount
case .accountDAOGetAll: return .accountDAOGetAll
case .accountDAOGetAllCantDecode: return .accountDAOGetAllCantDecode
case .accountDAOFindBy: return .accountDAOFindBy

View File

@ -177,6 +177,10 @@ public enum ZcashErrorCode: String {
case rustGetWalletSummary = "ZRUST0056"
/// Error from rust layer when calling ZcashRustBackend.
case rustProposeTransferFromURI = "ZRUST0057"
/// Error from rust layer when calling ZcashRustBackend.
case rustListAccounts = "ZRUST0058"
/// Error from rust layer when calling ZcashRustBackend.rustIsSeedRelevantToAnyDerivedAccount
case rustIsSeedRelevantToAnyDerivedAccount = "ZRUST0059"
/// SQLite query failed when fetching all accounts from the database.
case accountDAOGetAll = "ZADAO0001"
/// Fetched accounts from SQLite but can't decode them.

View File

@ -352,6 +352,14 @@ enum ZcashErrorDefinition {
/// - `rustError` contains error generated by the rust layer.
// sourcery: code="ZRUST0057"
case rustProposeTransferFromURI(_ rustError: String)
/// Error from rust layer when calling ZcashRustBackend.
/// - `rustError` contains error generated by the rust layer.
// sourcery: code="ZRUST0058"
case rustListAccounts(_ rustError: String)
/// Error from rust layer when calling ZcashRustBackend.rustIsSeedRelevantToAnyDerivedAccount
/// - `rustError` contains error generated by the rust layer.
// sourcery: code="ZRUST0059"
case rustIsSeedRelevantToAnyDerivedAccount(_ rustError: String)
// MARK: - Account DAO

View File

@ -120,7 +120,6 @@ public class Initializer {
let saplingParamsSourceURL: SaplingParamsSourceURL
var lightWalletService: LightWalletService
let transactionRepository: TransactionRepository
let accountRepository: AccountRepository
let storage: CompactBlockRepository
var blockDownloaderService: BlockDownloaderService
let network: ZcashNetwork
@ -272,12 +271,6 @@ public class Initializer {
self.alias = alias
self.lightWalletService = container.resolve(LightWalletService.self)
self.transactionRepository = container.resolve(TransactionRepository.self)
self.accountRepository = AccountRepositoryBuilder.build(
dataDbURL: urls.dataDbURL,
readOnly: true,
caching: true,
logger: container.resolve(Logger.self)
)
self.storage = container.resolve(CompactBlockRepository.self)
self.blockDownloaderService = container.resolve(BlockDownloaderService.self)
self.network = network
@ -419,7 +412,7 @@ public class Initializer {
self.walletBirthday = checkpoint.height
// If there are no accounts it must be created, the default amount of accounts is 1
if let seed, try accountRepository.getAll().isEmpty {
if let seed, try await rustBackend.listAccounts().isEmpty {
var chainTip: UInt32?
if walletMode == .restoreWallet {

View File

@ -21,9 +21,10 @@ public struct PoolBalance: Equatable {
public struct AccountBalance: Equatable {
public let saplingBalance: PoolBalance
public let orchardBalance: PoolBalance
public let unshielded: Zatoshi
static let zero = AccountBalance(saplingBalance: .zero, unshielded: .zero)
static let zero = AccountBalance(saplingBalance: .zero, orchardBalance: .zero, unshielded: .zero)
}
struct ScanProgress: Equatable {
@ -53,4 +54,5 @@ struct WalletSummary: Equatable {
let fullyScannedHeight: BlockHeight
let scanProgress: ScanProgress?
let nextSaplingSubtreeIndex: UInt32
let nextOrchardSubtreeIndex: UInt32
}

View File

@ -223,14 +223,12 @@ extension LightWalletGRPCService: LightWalletService {
do {
guard let reply = try await iterator.next() else { return nil }
return UTXO(
id: nil,
address: reply.address,
prevoutTxId: reply.txid,
prevoutIndex: Int(reply.index),
script: reply.script,
valueZat: Int(reply.valueZat),
height: Int(reply.height),
spentInTx: nil
height: Int(reply.height)
)
} catch {
let serviceError = error.mapToServiceError()
@ -278,6 +276,10 @@ extension LightWalletGRPCService: LightWalletService {
}
}
func getTreeState(_ id: BlockID) async throws -> TreeState {
try await compactTxStreamer.getTreeState(id)
}
func closeConnection() {
_ = channel.close()
}

View File

@ -196,4 +196,6 @@ protocol LightWalletService: AnyObject {
/// - Parameters:
/// - request: Request to send to GetSubtreeRoots.
func getSubtreeRoots(_ request: GetSubtreeRootsArg) -> AsyncThrowingStream<SubtreeRoot, Error>
func getTreeState(_ id: BlockID) async throws -> TreeState
}

View File

@ -1,15 +0,0 @@
//
// UnspentTransactionOutputRepository.swift
// ZcashLightClientKit
//
// Created by Francisco Gindre on 12/11/20.
//
import Foundation
protocol UnspentTransactionOutputRepository {
func initialise() async throws
func getAll(address: String?) async throws -> [UnspentTransactionOutputEntity]
func store(utxos: [UnspentTransactionOutputEntity]) async throws
func clearAll(address: String?) async throws
}

View File

@ -0,0 +1,8 @@
{
"network": "main",
"height": "2430000",
"hash": "0000000000125ca44e9fcf4cc3dcca62ea97fe57675de5f4eefff14019da9c59",
"time": 1710019165,
"saplingTree": "0180dc86263144bf0578faef14fe255918b3daa7f6575e3219a45f84c58aadb565001a00013f49b7b4e8dab0710793531f5b17721583682b01b3ddf268b1a1683fbff52506015523cd9344fe1ef83e00b455846e900a1b5deb413cb6a55103358e5b5294222d00000159eca2abc6624a885838426a0b57bf19334e730f02d2496365c5aac0f81a6c0901ce005d7ec39cdff90a74856266d2a1a299651274faa215522ee152facc7296670000010f496f195cbf0b25829ab6822834a2aff38ef2ddabc4554b3c743c0b4e9277320001330ac2cf864d6286bc980e689309f15471c479d5ce5349e47329459c834f8b0e0178f9d1c5155d10cb72343cdba0308148656de82cacf5665a8d8bd13b7c9a932500000132c525343fc4ebe79ab6515e9d9fceb916d920394bad5926a1afe7f46badef420001d1b36bbba8e6e1be8f09baf2b829bafc4ccd89ad25fb730d2b8a995b60fc3a6701d8ccea507421a590ed38116b834189cdc22421b4764179fa4e364803dfa66d56018cf6f5034a55fed59d1d832620916a43c756d2379e50ef9440fc4c3e7a29aa2300011619f99023a69bb647eab2d2aa1a73c3673c74bb033c3c4930eacda19e6fd93b0000000160272b134ca494b602137d89e528c751c06d3ef4a87a45f33af343c15060cc1e",
"orchardTree": "0156a89f3f7f90d5f432cda7fff64aebdf9985682f367ea3487a39a214519cd42a0148de740daab68ea109932f8fa094c0c366fed18b1303a4dd21477a0f319d762e1f0143c1a60d9f30927b79e9cb6c811d5d51bbd35618d126e0af5bef10510c5b541c0131343cbd09085b36a3c659324542f02edbbe0c15c1f112267e075f1d6c57c4200001716145dbe0fc2ba71a8d9ad9441fbff828b681a93f6396be7b07698428c7af1800000100306d1f79c74ca0425b6c4885f58e72a4d696489e05d4ed223cded613f3040c000141b0bc00892aa321cef46ca03e784f6c521834e77944776244b76c3ab566fc2f01c27e5a58efba5a37af4d6b5e9838249f972672372a6b9a85346be924e64e5d1c000133ebf1946b8daef9af45b0105f8ddc87f406da6552ce60cb837e9b6323df8e020001dc8f099e807208a39136acdae660ffd7fa2c9fca740c623f73c152cf2958563d0001d386508c9fabdc60836bfe3c7251fcbdd4617180a804d40fa29dc25fb9c0aa3401cf3bf92f69798e68555548afcce1648add1fb2548d64fa9a1ec22a3e26e7890101e637281deb58dff0c44ba13149b784a95da1b493005efd057e6f4ac20ef5d81d000001cc2dcaa338b312112db04b435a706d63244dd435238f0aa1e9e1598d35470810012dcc4273c8a0ed2337ecf7879380a07e7d427c7f9d82e538002bd1442978402c01daf63debf5b40df902dae98dadc029f281474d190cddecef1b10653248a234150001e2bca6a8d987d668defba89dc082196a922634ed88e065c669e526bb8815ee1b000000000000"
}

View File

@ -0,0 +1,8 @@
{
"network": "main",
"height": "2432500",
"hash": "00000000006bab4115f085ee76d0db4f993a10be75d234718b13fdff118f592d",
"time": 1710207121,
"saplingTree": "01f801cbf5eb3c278d735c90c3d016d86d781521c85d23f094da5b95bd7f5e7601014efb10c23ae510a46478c2a8effacd37bb695d8e5eb23d7a2b45b406c585e1621a0001c031081d455edcccc55e591c8c2047f59ee6b17fac5d60922a5dab1615e65f41018ea8aac2c80557b07c35844b0a5f994511975dde8ae2a93a78799f2d5bb01f0a01d777f1bb4e1c42d6888a983d8443c203d9d91c193c391e7b18ce15161a34ba5c0001954cc72390c04c20e0f4b6d9af7f370fc7341985f60f95d6bc894ee5bdea8572019f85951f4496c4a96844f9de83606be8a9aa09c0d5f26aa1393a98505398fc4200000001592739b2ff134389decac775f21d3aa2a0d67168e3a45add204fb70e25115d6201330ac2cf864d6286bc980e689309f15471c479d5ce5349e47329459c834f8b0e0178f9d1c5155d10cb72343cdba0308148656de82cacf5665a8d8bd13b7c9a932500000132c525343fc4ebe79ab6515e9d9fceb916d920394bad5926a1afe7f46badef420001d1b36bbba8e6e1be8f09baf2b829bafc4ccd89ad25fb730d2b8a995b60fc3a6701d8ccea507421a590ed38116b834189cdc22421b4764179fa4e364803dfa66d56018cf6f5034a55fed59d1d832620916a43c756d2379e50ef9440fc4c3e7a29aa2300011619f99023a69bb647eab2d2aa1a73c3673c74bb033c3c4930eacda19e6fd93b0000000160272b134ca494b602137d89e528c751c06d3ef4a87a45f33af343c15060cc1e",
"orchardTree": "0131bcbe72d425937ecf12a1b1422712c41b7db05ce31d628055c60fad4a3cba19001f0000000001b5d9ddd00c0a0e0152884719008b94484a34e23596e12fe227941268eb1a5f2001614a42b07e005bb98d37927ad44a63b8683ed4dccb9ff5953ff1c8d356598a2a01c9e9f49555ca08e75c03b3c8be117042bfbd04642437c01ce740428dead53c2d012661350c44f41f1adf0ee682fbda495de5d5b228cb063acd360d9ffe18188b390000019b11e54b92195de900cea1584a17b7238cabdb2605c04202ff900405eab301220133ebf1946b8daef9af45b0105f8ddc87f406da6552ce60cb837e9b6323df8e020001dc8f099e807208a39136acdae660ffd7fa2c9fca740c623f73c152cf2958563d0001d386508c9fabdc60836bfe3c7251fcbdd4617180a804d40fa29dc25fb9c0aa3401cf3bf92f69798e68555548afcce1648add1fb2548d64fa9a1ec22a3e26e7890101e637281deb58dff0c44ba13149b784a95da1b493005efd057e6f4ac20ef5d81d000001cc2dcaa338b312112db04b435a706d63244dd435238f0aa1e9e1598d35470810012dcc4273c8a0ed2337ecf7879380a07e7d427c7f9d82e538002bd1442978402c01daf63debf5b40df902dae98dadc029f281474d190cddecef1b10653248a234150001e2bca6a8d987d668defba89dc082196a922634ed88e065c669e526bb8815ee1b000000000000"
}

View File

@ -0,0 +1,8 @@
{
"network": "main",
"height": "2435000",
"hash": "00000000009bd2c651d8ae1c17d68044331d1fc31706e319653a6987f7ebf6ec",
"time": 1710395535,
"saplingTree": "0173b53d084813832ff9f2bb94af02621366d65cf5cb6199b7efc4bb37a4f9b72d014502f1327e3618b1358faf277fb1ceae01350ac12decaeba47150536cc04a3641a01e5e8fa0ca6544b3e2c6963efa86ad4013c8bff3e534a8f2c18fac7e8fcc643640103bde549304b260340bac0123c6defc3c8038e23e54161803ff10e7bfbf2e523013a7b35839d4c73f402370a538ef270a3a560ae93171f7395c65e6fa39381254901a549da8bea62adb1667f4ff4c67d0563d32e31b66f261430bd743952c126626e01026de477715a88c4129cddd86ef5c2c08b644a604a3aa6bcf5a3a1b4d15d2f4f019152f8070c760fbeadfbd65c5123aacd3f6d5cf8e4d2a127b4689d2085b714460188fd1ca704f246922548a7fe0a31ea0d9fc59a8a1d65775173dd226dc89f336a000001c2fdb92d6aa7abfa3412e7e064391ac65080907fe6e6277b48c290f58825da3a01592739b2ff134389decac775f21d3aa2a0d67168e3a45add204fb70e25115d6201330ac2cf864d6286bc980e689309f15471c479d5ce5349e47329459c834f8b0e0178f9d1c5155d10cb72343cdba0308148656de82cacf5665a8d8bd13b7c9a932500000132c525343fc4ebe79ab6515e9d9fceb916d920394bad5926a1afe7f46badef420001d1b36bbba8e6e1be8f09baf2b829bafc4ccd89ad25fb730d2b8a995b60fc3a6701d8ccea507421a590ed38116b834189cdc22421b4764179fa4e364803dfa66d56018cf6f5034a55fed59d1d832620916a43c756d2379e50ef9440fc4c3e7a29aa2300011619f99023a69bb647eab2d2aa1a73c3673c74bb033c3c4930eacda19e6fd93b0000000160272b134ca494b602137d89e528c751c06d3ef4a87a45f33af343c15060cc1e",
"orchardTree": "012106c64514bac7ec475a8a3d956d1b252914cfd5b8e9a7e9a31e45c7b3706a38001f013875f1718df2e5825687dbd3c34e42506c4229032859a54404089bee053bfe37016fa782e38939d93fbbd1ec50d5e01e2381fbdc7ea453cd1aee635d62c40e8b200001e405453d111dc46d380c5ad29b8e28949f56a0f6c9e78265816441f392fac9230001bf291a84889c2f239a02cc81fc4851dad66d2c05f078fa3dfabf8bde4c0e840900015820a68951f0c8c823490b8fff96bf4964a2e0a87a823edcbadce0086480cd3800019b71db011e11c95751c9a7c91bf62b9a92f665e3067924281647a93b614c7327019b11e54b92195de900cea1584a17b7238cabdb2605c04202ff900405eab301220133ebf1946b8daef9af45b0105f8ddc87f406da6552ce60cb837e9b6323df8e020001dc8f099e807208a39136acdae660ffd7fa2c9fca740c623f73c152cf2958563d0001d386508c9fabdc60836bfe3c7251fcbdd4617180a804d40fa29dc25fb9c0aa3401cf3bf92f69798e68555548afcce1648add1fb2548d64fa9a1ec22a3e26e7890101e637281deb58dff0c44ba13149b784a95da1b493005efd057e6f4ac20ef5d81d000001cc2dcaa338b312112db04b435a706d63244dd435238f0aa1e9e1598d35470810012dcc4273c8a0ed2337ecf7879380a07e7d427c7f9d82e538002bd1442978402c01daf63debf5b40df902dae98dadc029f281474d190cddecef1b10653248a234150001e2bca6a8d987d668defba89dc082196a922634ed88e065c669e526bb8815ee1b000000000000"
}

View File

@ -0,0 +1,8 @@
{
"network": "main",
"height": "2437500",
"hash": "0000000001660722f6b67144e7f46c6839bcf186fd271e9d8a2c9ee52c507141",
"time": 1710584940,
"saplingTree": "01d933677fe8d163bdd3d862ac9630ec9767a9a8df71720d565bd6cba48f2d8d5d011e1c64cc7ce901d49d02585d9321611cfc7491a8d3922e6414b57fb72abd20421a01414c13577c3343a61ba87c0cd147a813aa802505e9ebf69260a7d2d445498c540000010cd4f39dfe5d870f200d8170677fa72cd61589eaf27c9a3f643de0e5f17cee0d016c53ad3a61d97ec6459d1ccdfd305bb0954e6b5242b52579f4c58b3a448f380301384a3a811c1f78c671187e2124e06a0f3f3aa35f725917d92b9b3b557621e72e01ebc8afd1ee40675e5f7390e7943d196d7d4157185c888ef6c01f2d8b178a777000000000000001e3644c42c5d7ecd832a2c662dcd397824930ebe37b37bc61ec5af84f724c2571000132c525343fc4ebe79ab6515e9d9fceb916d920394bad5926a1afe7f46badef420001d1b36bbba8e6e1be8f09baf2b829bafc4ccd89ad25fb730d2b8a995b60fc3a6701d8ccea507421a590ed38116b834189cdc22421b4764179fa4e364803dfa66d56018cf6f5034a55fed59d1d832620916a43c756d2379e50ef9440fc4c3e7a29aa2300011619f99023a69bb647eab2d2aa1a73c3673c74bb033c3c4930eacda19e6fd93b0000000160272b134ca494b602137d89e528c751c06d3ef4a87a45f33af343c15060cc1e",
"orchardTree": "010f988985056887ac24576fb86acddff6c668c69f72160aaeebc5bbfd8fc3f60c01dbdd7a0fea320e6902a517af8e719befd858e8aab433275f72ff8099dfaa09141f0000017d84bd6e8417ae9c490b51635ee59175611d6223b530ed8b4cc301bb836e4b35014b6da84ed7616c286ae41932575be5a18b22c4a650376426a4a3c450b13d542801786e7a1e8da6e69955ce02a79a121354eb11530ae5fb40b4340e17ce0ea5093d0000000000000001b317414af14283ac9ab63130ea6700eda06ec5f0702aa83a4b168a0e4eba773d01dc8f099e807208a39136acdae660ffd7fa2c9fca740c623f73c152cf2958563d0001d386508c9fabdc60836bfe3c7251fcbdd4617180a804d40fa29dc25fb9c0aa3401cf3bf92f69798e68555548afcce1648add1fb2548d64fa9a1ec22a3e26e7890101e637281deb58dff0c44ba13149b784a95da1b493005efd057e6f4ac20ef5d81d000001cc2dcaa338b312112db04b435a706d63244dd435238f0aa1e9e1598d35470810012dcc4273c8a0ed2337ecf7879380a07e7d427c7f9d82e538002bd1442978402c01daf63debf5b40df902dae98dadc029f281474d190cddecef1b10653248a234150001e2bca6a8d987d668defba89dc082196a922634ed88e065c669e526bb8815ee1b000000000000"
}

View File

@ -0,0 +1,8 @@
{
"network": "main",
"height": "2440000",
"hash": "00000000018aa1792888e7f52aaa4a491f9fbc8b2b3cbf2f7c61bce55925fe1a",
"time": 1710773380,
"saplingTree": "01fb1ad6730d051bdce7784d776ffff105824535c01bf4542d76b924198a69704a011f5c0e0f6e2c9bc44c22261c15dec4ef3810faf7491769a8e055a5000278650f1a015df95e48fc0ad9928390fd6c3ae09902c837fbaee45b4c603b88f67fdb5d962a0001d3918aa18fa1e5d1d7fd19f19ad8439d724c4d5c19a980c7761c688a3289810201494d3878deb5d888ceb5686851f72473527e8f8e4ce04fcbeae9df0c02d90301000000000001686eb402fba0131374aefd1da61e310a7b378c7b3085c0216234b0c9073fa32c00000001e3644c42c5d7ecd832a2c662dcd397824930ebe37b37bc61ec5af84f724c2571000132c525343fc4ebe79ab6515e9d9fceb916d920394bad5926a1afe7f46badef420001d1b36bbba8e6e1be8f09baf2b829bafc4ccd89ad25fb730d2b8a995b60fc3a6701d8ccea507421a590ed38116b834189cdc22421b4764179fa4e364803dfa66d56018cf6f5034a55fed59d1d832620916a43c756d2379e50ef9440fc4c3e7a29aa2300011619f99023a69bb647eab2d2aa1a73c3673c74bb033c3c4930eacda19e6fd93b0000000160272b134ca494b602137d89e528c751c06d3ef4a87a45f33af343c15060cc1e",
"orchardTree": "0147a6f9d105380685acaf06121f4a4e73255cf306c7489f47e4637d4bce0e350201d6de40cf0031826655d3f106cd06b0ecf624d37040e38ec3c06fbd55547fda251f00012b8bc0c564cd98f599d12a041ef1d914cbe56d9d9208485d5ebe9ccb580bc60201072a949f5f31122af6b80e1e62396506d6a5cbabf08345481e221e55ad05f23b0000013a8bd26f29c49b7c8f0aa02ef6f95284b145e1b281eaf357e0042f83a0430624000163efdc4ca36aec225b76e1a60a69faf152d119f78afc277979696b91ab1ec62d012d2d92046864657193f8957b2a17382634c4197cd6de95d316e721260c99193300000001b317414af14283ac9ab63130ea6700eda06ec5f0702aa83a4b168a0e4eba773d01dc8f099e807208a39136acdae660ffd7fa2c9fca740c623f73c152cf2958563d0001d386508c9fabdc60836bfe3c7251fcbdd4617180a804d40fa29dc25fb9c0aa3401cf3bf92f69798e68555548afcce1648add1fb2548d64fa9a1ec22a3e26e7890101e637281deb58dff0c44ba13149b784a95da1b493005efd057e6f4ac20ef5d81d000001cc2dcaa338b312112db04b435a706d63244dd435238f0aa1e9e1598d35470810012dcc4273c8a0ed2337ecf7879380a07e7d427c7f9d82e538002bd1442978402c01daf63debf5b40df902dae98dadc029f281474d190cddecef1b10653248a234150001e2bca6a8d987d668defba89dc082196a922634ed88e065c669e526bb8815ee1b000000000000"
}

View File

@ -0,0 +1,8 @@
{
"network": "main",
"height": "2442500",
"hash": "0000000000e01a9fdf001f3e7ce37f97297dfda65565cee2a5647e1dabf6e58d",
"time": 1710961233,
"saplingTree": "013c37d2664456cbe5c5e48c64dfea53f515ecfa2348b8f8d059f18fb2b622d5200126cc3c024b182b258d5ac3f1bb6c8047ff3d21a5f90d757e29badd8b9e2e120c1a000187b7910243390d4a57950e3726c20cc6196c9f3de6cc35ddeb05cf3a91b3b22300010d5f518de07315aa39a8f19c8ec857fc701f1b1d036acb57080868e4d23b94190001096a541cee2d3c64952753d284a757ce67d4ca13ac9b66d89d046c4b62d0e91a01d9ce6bbf0494ab1efa765d32e6f0431e6aded3fa205070aa19531aa7d1bffa06017190666f6837d3449d345f4077c8e6aa5b53a0e0c52c002f1047215e98d269060145acf941b65c7966c03a210db51db76756886d6f3c6671b9ed2df37db53ab74701686eb402fba0131374aefd1da61e310a7b378c7b3085c0216234b0c9073fa32c00000001e3644c42c5d7ecd832a2c662dcd397824930ebe37b37bc61ec5af84f724c2571000132c525343fc4ebe79ab6515e9d9fceb916d920394bad5926a1afe7f46badef420001d1b36bbba8e6e1be8f09baf2b829bafc4ccd89ad25fb730d2b8a995b60fc3a6701d8ccea507421a590ed38116b834189cdc22421b4764179fa4e364803dfa66d56018cf6f5034a55fed59d1d832620916a43c756d2379e50ef9440fc4c3e7a29aa2300011619f99023a69bb647eab2d2aa1a73c3673c74bb033c3c4930eacda19e6fd93b0000000160272b134ca494b602137d89e528c751c06d3ef4a87a45f33af343c15060cc1e",
"orchardTree": "01a27c9df6e1009152c5db2fffc3856f7c8cadb89a09f0833c96c1dfa2fc99cf08015ec5a59c4dff47ede70f4cbfc27d7227ee6c0938d8443c8306f64a3df13d56311f01f62d858afe1f4d37fa975b07789c65b1ef16e67cb2d4301990d190fd05da4e3d000198f59f323fdb55dc69ce636f9055de6cf4d0e6110343f747455c2cb9e417563b0001091ca87e38804d889c942f751df05c73c66c898cdf612cd32fc1d0924acf8113000107d607af6e0d90e878cab9c443ccc3c2ffb2d1787ff4a98cf393cb41bf4314330001636f6be10fb282255101364ff07e3d36455ca24a681654340b185edfb3d5f92f019b57450e5ceaa159777d6ba338f6932d560e5e1d0fb7e0b9f6851e4aeff6d220000001b317414af14283ac9ab63130ea6700eda06ec5f0702aa83a4b168a0e4eba773d01dc8f099e807208a39136acdae660ffd7fa2c9fca740c623f73c152cf2958563d0001d386508c9fabdc60836bfe3c7251fcbdd4617180a804d40fa29dc25fb9c0aa3401cf3bf92f69798e68555548afcce1648add1fb2548d64fa9a1ec22a3e26e7890101e637281deb58dff0c44ba13149b784a95da1b493005efd057e6f4ac20ef5d81d000001cc2dcaa338b312112db04b435a706d63244dd435238f0aa1e9e1598d35470810012dcc4273c8a0ed2337ecf7879380a07e7d427c7f9d82e538002bd1442978402c01daf63debf5b40df902dae98dadc029f281474d190cddecef1b10653248a234150001e2bca6a8d987d668defba89dc082196a922634ed88e065c669e526bb8815ee1b000000000000"
}

View File

@ -0,0 +1,8 @@
{
"network": "main",
"height": "2445000",
"hash": "000000000032ba3efc3e8c1c10a6dad5ddc4db01889b5cf8c3b83287c00bc2ae",
"time": 1711150054,
"saplingTree": "01efe79fb76d25d5b8aa76362acfa7adc18c52768681b30bffa8957d7dd1952d17001a00000000000001809e9ee7a27e8dcca3be914d59ae9c6aa569381ab12ec681cd94755169b83a2f01c1e8caa49f92f0b9998e63055056856ed7c243f3c4b01d079a7c400e73dbee6e016a4e2d8a2667d5f784a6ad1837e0c294884b4277daa35487510c95236aee69070001661a4760490eaebe48d77a020c789562c029750e16c01cfd195b960a1d7f9248000001e3644c42c5d7ecd832a2c662dcd397824930ebe37b37bc61ec5af84f724c2571000132c525343fc4ebe79ab6515e9d9fceb916d920394bad5926a1afe7f46badef420001d1b36bbba8e6e1be8f09baf2b829bafc4ccd89ad25fb730d2b8a995b60fc3a6701d8ccea507421a590ed38116b834189cdc22421b4764179fa4e364803dfa66d56018cf6f5034a55fed59d1d832620916a43c756d2379e50ef9440fc4c3e7a29aa2300011619f99023a69bb647eab2d2aa1a73c3673c74bb033c3c4930eacda19e6fd93b0000000160272b134ca494b602137d89e528c751c06d3ef4a87a45f33af343c15060cc1e",
"orchardTree": "01e6226f66172d9b52de8f3efd1722cf3d9de4878df0ca0230ddf95f87e1e5ae31001f0001c949193b4d40d7b25181b2885dbb0ee41bf0bc53b37ac2f1cbddd6e00ceca4100001c2220a8a49fdb47edadd405a43039ca69c9158fde74ccbb5c6838464cc563b260001f46913c82ab9854fbb2a2207cca3e397a8f23903c0be58e3d26536e1b08b110b01c12cf5c3940490167a7753ede643275e47e137902c9287b1be84ca962da9f310010b4d4cb8f25e5ac4228aaa6b84ca38ce7e1563c26a594bcc7944794bce41fa2e000001818f8b592633baf0d32d20b6bdf8fc1f0383a20c95f949fdf871466c288789140001b317414af14283ac9ab63130ea6700eda06ec5f0702aa83a4b168a0e4eba773d01dc8f099e807208a39136acdae660ffd7fa2c9fca740c623f73c152cf2958563d0001d386508c9fabdc60836bfe3c7251fcbdd4617180a804d40fa29dc25fb9c0aa3401cf3bf92f69798e68555548afcce1648add1fb2548d64fa9a1ec22a3e26e7890101e637281deb58dff0c44ba13149b784a95da1b493005efd057e6f4ac20ef5d81d000001cc2dcaa338b312112db04b435a706d63244dd435238f0aa1e9e1598d35470810012dcc4273c8a0ed2337ecf7879380a07e7d427c7f9d82e538002bd1442978402c01daf63debf5b40df902dae98dadc029f281474d190cddecef1b10653248a234150001e2bca6a8d987d668defba89dc082196a922634ed88e065c669e526bb8815ee1b000000000000"
}

View File

@ -0,0 +1,8 @@
{
"network": "main",
"height": "2447500",
"hash": "00000000012db8b5bdd6c44c6fbeeee7b24bbb7f14a214cbf678510a59cadf3f",
"time": 1711338099,
"saplingTree": "0121c86d5e6ffa93ef5a3734a836b560782a6e700129e8b9feb9052042fb87be2a012f9ac3bdebbbe0387ec38dba15faeabac24e6d136a5f2d8f8a9a811c596adc3c1a0001d876c965043694af1e4e8413d8aeea1e53517b3959796eb93b3dcfdba2b60168018dd52ff0b5454c74f69c84cf4ef73f2370811ff361cdf3f170f3700f0c3d110e0180955ea26df3668f83bac3a8f2961db643070703421e9132385c8ad43a9ea2460000010f6dbc8b6394ebb5950a4fd6b5796771ce2f6ed93aee9c44b0066cb994a137560001895d803e6d1a96ffed6e66c8d5b1f9611b330bcf3d8c77fc828619f239236610010ebeeae59b247f37eeb6aa57dc2e52f4b965c69864809b1f6cafcd0534d0221601661a4760490eaebe48d77a020c789562c029750e16c01cfd195b960a1d7f9248000001e3644c42c5d7ecd832a2c662dcd397824930ebe37b37bc61ec5af84f724c2571000132c525343fc4ebe79ab6515e9d9fceb916d920394bad5926a1afe7f46badef420001d1b36bbba8e6e1be8f09baf2b829bafc4ccd89ad25fb730d2b8a995b60fc3a6701d8ccea507421a590ed38116b834189cdc22421b4764179fa4e364803dfa66d56018cf6f5034a55fed59d1d832620916a43c756d2379e50ef9440fc4c3e7a29aa2300011619f99023a69bb647eab2d2aa1a73c3673c74bb033c3c4930eacda19e6fd93b0000000160272b134ca494b602137d89e528c751c06d3ef4a87a45f33af343c15060cc1e",
"orchardTree": "019a450901c143c43ea51cdbcf8b6de8b5a8d05f6d55845cb5f15d50663f819217015be7f0cffa838a09fa378bf699d218fc7674dc7bd99a525261adca4bfe9e002e1f00010a7ae37530c3b644773eebafaf8a9a15e46d7bbeed3e902b084529978976e53900017baad349203e05ed63da22471b555136cfd8bed26590ac9f7826442c568bc923000000012288799495392e86b155ddd18069b8eafb2402a33af2a1b5b16093a0c48bfa2d0001c81341a707a972d0f388802e56c99c58257eae60b6dbd44b537e70d097579a3301818f8b592633baf0d32d20b6bdf8fc1f0383a20c95f949fdf871466c288789140001b317414af14283ac9ab63130ea6700eda06ec5f0702aa83a4b168a0e4eba773d01dc8f099e807208a39136acdae660ffd7fa2c9fca740c623f73c152cf2958563d0001d386508c9fabdc60836bfe3c7251fcbdd4617180a804d40fa29dc25fb9c0aa3401cf3bf92f69798e68555548afcce1648add1fb2548d64fa9a1ec22a3e26e7890101e637281deb58dff0c44ba13149b784a95da1b493005efd057e6f4ac20ef5d81d000001cc2dcaa338b312112db04b435a706d63244dd435238f0aa1e9e1598d35470810012dcc4273c8a0ed2337ecf7879380a07e7d427c7f9d82e538002bd1442978402c01daf63debf5b40df902dae98dadc029f281474d190cddecef1b10653248a234150001e2bca6a8d987d668defba89dc082196a922634ed88e065c669e526bb8815ee1b000000000000"
}

View File

@ -0,0 +1,8 @@
{
"network": "test",
"height": "2750000",
"hash": "0032ee34dff008317a8b7078198e3e62a30d41b041bc821c07f2481d93fbcb59",
"time": 1710015877,
"saplingTree": "01dd6271359272245882abb3e2bb9d5500d92153adcff74977dcd8d00b38bb280c01cd5d69cb79696e6183abb1884a64aeecbdc6636daed5760b0c3dbb8239c8616e100000000000016dd9892b9c2e5daf14b579e607b515374d5b29f44bfd1eda0cc44902e7ce4d11016526e08f5ea3f5e89c8434a0b0249642b86354dc00c32f0c104e802a0e0eaf6000000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39",
"orchardTree": "01e8865e5c0fec206805c50225066d28461cec4791744c8a4269fff48caf8c563f015f41071dacad598328cdb0603154ed656b9ec65d00295cf93afc6a392c666f241f0171152098d19f906049dfd98c777a5ccd5f9d3f8b80d4ced4dac79d125a0a3e13013488aaf56dde9d60d789c8bfc346baf09cd209070ded9d15f2d455cc86c44b040000000001fcb318566b2a3c4812c1ac1ffeb99226c2c653094bedf9608cf409ffc54e18200172316ba203fdc9df151f6101a287f203befcd8bdecac5cf43a2f421d6a467f080000011e6191f91b3fceb62dc881a156e1b9d2e88e09dca25093cf9c4936c8869fb41a013bf8b923e4187754e85175748d9cce4824a6787e4258977b5bfe1ba59012c032000001f3bbdc62260c4fca5c84bf3487246d4542da48eeeec8ec40c1029b6908eef83c00000000000000000000000000000000"
}

View File

@ -0,0 +1,8 @@
{
"network": "test",
"height": "2760000",
"hash": "001e7783656e6d9801bbd49483da9798b321626ebdf606993a5c68b40f2e636f",
"time": 1710643466,
"saplingTree": "0137552d8794f50ca3e6d8c04b79641c61531137a36e0c16797c7b4042dcfb2922001001efd0586745505fa5c1358a4976f0511cb08d32f808ce45e0874ce84bc03767010001b73c4685a80e900cc7f3f31b0808ae5e31f744a934bf530870f762daaf55a6440114fdc3f78cb10a1daa80e89f40d4834e7964e7fbe0f12cd3d346a23739d3eb2600016dd9892b9c2e5daf14b579e607b515374d5b29f44bfd1eda0cc44902e7ce4d11016526e08f5ea3f5e89c8434a0b0249642b86354dc00c32f0c104e802a0e0eaf6000000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39",
"orchardTree": "01def56c50751a5c5fbdc117450890b01c1bf37fa05daa9e1d318a09213080b70201980479154da09ad5cdd7b184a66b89cb544c9b46d83cfa4e9da11a5e0d935d0a1f000000000001061089b21464cd2d65ac65d509f398014d89f00a996ec0807a1da1f2ac88cc0d01fcb318566b2a3c4812c1ac1ffeb99226c2c653094bedf9608cf409ffc54e18200172316ba203fdc9df151f6101a287f203befcd8bdecac5cf43a2f421d6a467f080000011e6191f91b3fceb62dc881a156e1b9d2e88e09dca25093cf9c4936c8869fb41a013bf8b923e4187754e85175748d9cce4824a6787e4258977b5bfe1ba59012c032000001f3bbdc62260c4fca5c84bf3487246d4542da48eeeec8ec40c1029b6908eef83c00000000000000000000000000000000"
}

View File

@ -0,0 +1,8 @@
{
"network": "test",
"height": "2770000",
"hash": "00065215d6079640ddf94ac7414130f35efabc9d24c9fa8feefa86030f5e5dcf",
"time": 1711329173,
"saplingTree": "01df4ab40e947423f0d6e527bdf8f4bfb33bd9487d28632b1480dc454a51174f600010014af622a06b0138e40355cfb8905dcb0d3a24d8e0793d886763b0c53275b75b1b0001668c0700dbe3d5efa57cc583bd2ff8a0e547b31044f216f11f02e0982d74fe2e0000010c96e4cc8a6a80fba0d41e4eb3070d80769104dc33fb61133b1304c15bf9e23e000107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39",
"orchardTree": "01071ec35db52f66ce2ae4a131ba489adae60f7d028b928111abdcaa5784c597320150da3f6787f2d6ae4f48892554efb2e64d26b4e56f3d6ffe819770bee8ee851e1f0000000001c4ac2643a1b48b270cebdc0d99da3f8f4e52bcd6a81b2a681919661e91c6610901061089b21464cd2d65ac65d509f398014d89f00a996ec0807a1da1f2ac88cc0d01fcb318566b2a3c4812c1ac1ffeb99226c2c653094bedf9608cf409ffc54e18200172316ba203fdc9df151f6101a287f203befcd8bdecac5cf43a2f421d6a467f080000011e6191f91b3fceb62dc881a156e1b9d2e88e09dca25093cf9c4936c8869fb41a013bf8b923e4187754e85175748d9cce4824a6787e4258977b5bfe1ba59012c032000001f3bbdc62260c4fca5c84bf3487246d4542da48eeeec8ec40c1029b6908eef83c00000000000000000000000000000000"
}

View File

@ -49,6 +49,31 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
}
}
func listAccounts() async throws -> [Int32] {
globalDBLock.lock()
let accountsPtr = zcashlc_list_accounts(
dbData.0,
dbData.1,
networkType.networkId
)
globalDBLock.unlock()
guard let accountsPtr else {
throw ZcashError.rustListAccounts(lastErrorMessage(fallback: "`listAccounts` failed with unknown error"))
}
defer { zcashlc_free_accounts(accountsPtr) }
var accounts: [Int32] = []
for i in (0 ..< Int(accountsPtr.pointee.len)) {
let account = accountsPtr.pointee.ptr.advanced(by: i).pointee
accounts.append(Int32(account.account_index))
}
return accounts
}
func createAccount(seed: [UInt8], treeState: TreeState, recoverUntil: UInt32?) async throws -> UnifiedSpendingKey {
var rUntil: Int64 = -1
@ -80,6 +105,26 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
return ffiBinaryKeyPtr.pointee.unsafeToUnifiedSpendingKey(network: networkType)
}
func isSeedRelevantToAnyDerivedAccount(seed: [UInt8]) async throws -> Bool {
globalDBLock.lock()
let result = zcashlc_is_seed_relevant_to_any_derived_account(
dbData.0,
dbData.1,
seed,
UInt(seed.count),
networkType.networkId
)
globalDBLock.unlock()
// -1 is the error sentinel.
guard result >= 0 else {
throw ZcashError.rustIsSeedRelevantToAnyDerivedAccount(lastErrorMessage(fallback: "`isSeedRelevantToAnyDerivedAccount` failed with unknown error"))
}
// 0 is false, 1 is true.
return result != 0
}
func proposeTransfer(
account: Int32,
to address: String,
@ -298,6 +343,8 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
return DbInitResult.success
case 1:
return DbInitResult.seedRequired
case 2:
return DbInitResult.seedNotRelevant
default:
throw ZcashError.rustInitDataDb(lastErrorMessage(fallback: "`initDataDb` failed with unknown error"))
}
@ -589,7 +636,8 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
chainTipHeight: BlockHeight(summaryPtr.pointee.chain_tip_height),
fullyScannedHeight: BlockHeight(summaryPtr.pointee.fully_scanned_height),
scanProgress: summaryPtr.pointee.scan_progress?.pointee.toScanProgress(),
nextSaplingSubtreeIndex: UInt32(summaryPtr.pointee.next_sapling_subtree_index)
nextSaplingSubtreeIndex: UInt32(summaryPtr.pointee.next_sapling_subtree_index),
nextOrchardSubtreeIndex: UInt32(summaryPtr.pointee.next_orchard_subtree_index)
)
}
@ -623,9 +671,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 {
@ -841,6 +900,7 @@ extension FfiAccountBalance {
func toAccountBalance() -> AccountBalance {
.init(
saplingBalance: self.sapling_balance.toPoolBalance(),
orchardBalance: self.orchard_balance.toPoolBalance(),
unshielded: Zatoshi(self.unshielded)
)
}
@ -856,6 +916,7 @@ extension FfiScanProgress {
}
}
// swiftlint:disable large_tuple line_length
struct FfiTxId {
var tuple: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)
var array: [UInt8] {

View File

@ -11,15 +11,21 @@ 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
/// 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.
///
@ -41,6 +47,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 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.
@ -173,9 +184,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

View File

@ -351,6 +351,11 @@ public protocol Synchronizer: AnyObject {
/// - Throws: ZcashError when failures occur and related to `synchronizer.start(retry: Bool)`, it's the only throwing operation
/// during the whole endpoint change.
func switchTo(endpoint: LightWalletEndpoint) async throws
/// 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
}
public enum SyncStatus: Equatable {

View File

@ -100,8 +100,7 @@ enum Dependencies {
static func setupCompactBlockProcessor(
in container: DIContainer,
config: CompactBlockProcessor.Configuration,
accountRepository: AccountRepository
config: CompactBlockProcessor.Configuration
) {
container.register(type: BlockDownloader.self, isSingleton: true) { di in
let service = di.resolve(LightWalletService.self)
@ -120,6 +119,7 @@ enum Dependencies {
}
container.register(type: BlockScanner.self, isSingleton: true) { di in
let service = di.resolve(LightWalletService.self)
let rustBackend = di.resolve(ZcashRustBackendWelding.self)
let transactionRepository = di.resolve(TransactionRepository.self)
let metrics = di.resolve(SDKMetrics.self)
@ -133,6 +133,7 @@ enum Dependencies {
return BlockScannerImpl(
config: blockScannerConfig,
rustBackend: rustBackend,
service: service,
transactionRepository: transactionRepository,
metrics: metrics,
logger: logger
@ -163,7 +164,6 @@ enum Dependencies {
let logger = di.resolve(Logger.self)
return UTXOFetcherImpl(
accountRepository: accountRepository,
blockDownloaderService: blockDownloaderService,
config: utxoFetcherConfig,
rustBackend: rustBackend,

View File

@ -40,7 +40,6 @@ public class SDKSynchronizer: Synchronizer {
public let network: ZcashNetwork
private let transactionEncoder: TransactionEncoder
private let transactionRepository: TransactionRepository
private let utxoRepository: UnspentTransactionOutputRepository
private let syncSessionIDGenerator: SyncSessionIDGenerator
private let syncSession: SyncSession
@ -55,7 +54,6 @@ public class SDKSynchronizer: Synchronizer {
initializer: initializer,
transactionEncoder: WalletTransactionEncoder(initializer: initializer),
transactionRepository: initializer.transactionRepository,
utxoRepository: UTXORepositoryBuilder.build(initializer: initializer),
blockProcessor: CompactBlockProcessor(
initializer: initializer,
walletBirthdayProvider: { initializer.walletBirthday }
@ -69,7 +67,6 @@ public class SDKSynchronizer: Synchronizer {
initializer: Initializer,
transactionEncoder: TransactionEncoder,
transactionRepository: TransactionRepository,
utxoRepository: UnspentTransactionOutputRepository,
blockProcessor: CompactBlockProcessor,
syncSessionTicker: SessionTicker
) {
@ -78,7 +75,6 @@ public class SDKSynchronizer: Synchronizer {
self.initializer = initializer
self.transactionEncoder = transactionEncoder
self.transactionRepository = transactionRepository
self.utxoRepository = utxoRepository
self.blockProcessor = blockProcessor
self.network = initializer.network
self.metrics = initializer.container.resolve(SDKMetrics.self)
@ -137,8 +133,6 @@ public class SDKSynchronizer: Synchronizer {
throw error
}
try await utxoRepository.initialise()
if case .seedRequired = try await self.initializer.initialize(with: seed, walletBirthday: walletBirthday, for: walletMode) {
return .seedRequired
}
@ -309,8 +303,8 @@ public class SDKSynchronizer: Synchronizer {
uri,
accountIndex: accountIndex
)
} catch ZcashError.rustCreateToAddress(let e) {
throw ZcashError.rustProposeTransferFromURI(e)
} catch ZcashError.rustCreateToAddress(let error) {
throw ZcashError.rustProposeTransferFromURI(error)
} catch {
throw error
}
@ -502,25 +496,6 @@ public class SDKSynchronizer: Synchronizer {
try await blockProcessor.latestHeight()
}
public func latestUTXOs(address: String) async throws -> [UnspentTransactionOutputEntity] {
try throwIfUnprepared()
guard initializer.isValidTransparentAddress(address) else {
throw ZcashError.synchronizerLatestUTXOsInvalidTAddress
}
let stream = initializer.lightWalletService.fetchUTXOs(for: address, height: network.constants.saplingActivationHeight)
// swiftlint:disable:next array_constructor
var utxos: [UnspentTransactionOutputEntity] = []
for try await transactionEntity in stream {
utxos.append(transactionEntity)
}
try await self.utxoRepository.clearAll(address: address)
try await self.utxoRepository.store(utxos: utxos)
return utxos
}
public func refreshUTXOs(address: TransparentAddress, from height: BlockHeight) async throws -> RefreshedUTXOs {
try throwIfUnprepared()
return try await blockProcessor.refreshUTXOs(tAddress: address, startHeight: height)
@ -628,7 +603,11 @@ public class SDKSynchronizer: Synchronizer {
return subject.eraseToAnyPublisher()
}
public func isSeedRelevantToAnyDerivedAccount(seed: [UInt8]) async throws -> Bool {
try await initializer.rustBackend.isSeedRelevantToAnyDerivedAccount(seed: seed)
}
// MARK: Server switch
public func switchTo(endpoint: LightWalletEndpoint) async throws {
@ -692,8 +671,7 @@ public class SDKSynchronizer: Synchronizer {
// CompactBlockProcessor dependency update
Dependencies.setupCompactBlockProcessor(
in: initializer.container,
config: await blockProcessor.config,
accountRepository: initializer.accountRepository
config: await blockProcessor.config
)
// INITIALIZER

View File

@ -28,6 +28,10 @@ class AdvancedReOrgTests: ZcashTestCase {
override func setUp() async throws {
try await super.setUp()
mockContainer.mock(type: CheckpointSource.self, isSingleton: true) { _ in
return DarksideMainnetCheckpointSource()
}
// don't use an exact birthday, users never do.
self.coordinator = try await TestCoordinator(
container: mockContainer,

View File

@ -26,6 +26,10 @@ class BalanceTests: ZcashTestCase {
override func setUp() async throws {
try await super.setUp()
mockContainer.mock(type: CheckpointSource.self, isSingleton: true) { _ in
return DarksideMainnetCheckpointSource()
}
self.coordinator = try await TestCoordinator(
container: mockContainer,
walletBirthday: birthday,

View File

@ -10,7 +10,7 @@ import XCTest
@testable import TestUtils
@testable import ZcashLightClientKit
class BlockDownloaderTests: XCTestCase {
class BlockDownloaderTests: ZcashTestCase {
let branchID = "2bb40e60"
let chainName = "main"
@ -21,10 +21,14 @@ class BlockDownloaderTests: XCTestCase {
var storage: CompactBlockRepository!
var network = DarksideWalletDNetwork()
var rustBackend: ZcashRustBackendWelding!
var testTempDirectory: URL!
override func setUp() async throws {
try await super.setUp()
mockContainer.mock(type: CheckpointSource.self, isSingleton: true) { _ in
return DarksideMainnetCheckpointSource()
}
testTempDirectory = Environment.uniqueTestTempDirectory
service = LightWalletServiceFactory(endpoint: LightWalletEndpointBuilder.default).make()

View File

@ -27,6 +27,10 @@ class DarksideSanityCheckTests: ZcashTestCase {
override func setUp() async throws {
try await super.setUp()
mockContainer.mock (type: CheckpointSource.self, isSingleton: true) { _ in
return DarksideMainnetCheckpointSource()
}
self.coordinator = try await TestCoordinator(
container: mockContainer,
walletBirthday: birthday,

View File

@ -315,6 +315,7 @@ class PaymentURIFulfillmentTests: ZcashTestCase {
*/
let memo = "VGhpcyBpcyBhIHNpbXBsZSBtZW1vLg" // "This is a simple memo."
// swiftlint:disable:next line_length
let paymentURI = "zcash:zecIsGreat17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a?amount=0.0002&memo=\(memo)&message=Thank%20you%20for%20your%20purchase&label=Your%20Purchase"
do {

View File

@ -25,6 +25,10 @@ class PendingTransactionUpdatesTest: ZcashTestCase {
override func setUp() async throws {
try await super.setUp()
mockContainer.mock(type: CheckpointSource.self, isSingleton: true) { _ in
return DarksideMainnetCheckpointSource()
}
self.coordinator = try await TestCoordinator(
container: mockContainer,
walletBirthday: birthday,

View File

@ -44,6 +44,10 @@ class ReOrgTests: ZcashTestCase {
override func setUp() async throws {
try await super.setUp()
mockContainer.mock(type: CheckpointSource.self, isSingleton: true) { _ in
return DarksideMainnetCheckpointSource()
}
self.coordinator = try await TestCoordinator(
container: mockContainer,
walletBirthday: self.birthday,

View File

@ -25,6 +25,10 @@ class ShieldFundsTests: ZcashTestCase {
override func setUp() async throws {
try await super.setUp()
mockContainer.mock(type: CheckpointSource.self, isSingleton: true) { _ in
return DarksideMainnetCheckpointSource()
}
self.coordinator = try await TestCoordinator(
container: mockContainer,
walletBirthday: birthday,

View File

@ -30,6 +30,11 @@ class SynchronizerDarksideTests: ZcashTestCase {
override func setUp() async throws {
try await super.setUp()
mockContainer.mock(type: CheckpointSource.self, isSingleton: true) { _ in
return DarksideMainnetCheckpointSource()
}
let idGenerator = MockSyncSessionIDGenerator(ids: [.deadbeef])
mockContainer.mock(type: SyncSessionIDGenerator.self, isSingleton: false) { _ in idGenerator }
self.idGenerator = idGenerator

View File

@ -26,7 +26,11 @@ final class SynchronizerTests: ZcashTestCase {
override func setUp() async throws {
try await super.setUp()
mockContainer.mock(type: CheckpointSource.self, isSingleton: true) { _ in
return DarksideMainnetCheckpointSource()
}
// don't use an exact birthday, users never do.
self.coordinator = try await TestCoordinator(
container: mockContainer,

View File

@ -28,6 +28,10 @@ class Z2TReceiveTests: ZcashTestCase {
override func setUp() async throws {
try await super.setUp()
mockContainer.mock(type: CheckpointSource.self, isSingleton: true) { _ in
return DarksideMainnetCheckpointSource()
}
self.coordinator = try await TestCoordinator(
container: mockContainer,
walletBirthday: birthday,

View File

@ -638,7 +638,7 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
}
func testGetTransparentBalanceSucceed() {
let expectedBalance = AccountBalance(saplingBalance: .zero, unshielded: Zatoshi(200))
let expectedBalance = AccountBalance(saplingBalance: .zero, orchardBalance: .zero, unshielded: Zatoshi(200))
synchronizerMock.getAccountBalanceAccountIndexClosure = { receivedAccountIndex in
XCTAssertEqual(receivedAccountIndex, 3)
@ -685,7 +685,13 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
PoolBalance(
spendableValue: Zatoshi(333),
changePendingConfirmation: .zero,
valuePendingSpendability: .zero), unshielded: .zero
valuePendingSpendability: .zero),
orchardBalance:
PoolBalance(
spendableValue: Zatoshi(333),
changePendingConfirmation: .zero,
valuePendingSpendability: .zero),
unshielded: .zero
)
synchronizerMock.getAccountBalanceAccountIndexClosure = { receivedAccountIndex in
@ -733,7 +739,13 @@ class ClosureSynchronizerOfflineTests: XCTestCase {
PoolBalance(
spendableValue: .zero,
changePendingConfirmation: Zatoshi(333),
valuePendingSpendability: .zero), unshielded: .zero
valuePendingSpendability: .zero),
orchardBalance:
PoolBalance(
spendableValue: .zero,
changePendingConfirmation: Zatoshi(333),
valuePendingSpendability: .zero),
unshielded: .zero
)
synchronizerMock.getAccountBalanceAccountIndexClosure = { receivedAccountIndex in

View File

@ -748,7 +748,7 @@ class CombineSynchronizerOfflineTests: XCTestCase {
}
func testGetTransparentBalanceSucceed() {
let expectedBalance = AccountBalance(saplingBalance: .zero, unshielded: Zatoshi(100))
let expectedBalance = AccountBalance(saplingBalance: .zero, orchardBalance: .zero, unshielded: Zatoshi(100))
synchronizerMock.getAccountBalanceAccountIndexClosure = { receivedAccountIndex in
XCTAssertEqual(receivedAccountIndex, 3)
@ -809,6 +809,11 @@ class CombineSynchronizerOfflineTests: XCTestCase {
spendableValue: .zero,
changePendingConfirmation: Zatoshi(333),
valuePendingSpendability: .zero),
orchardBalance:
PoolBalance(
spendableValue: .zero,
changePendingConfirmation: Zatoshi(333),
valuePendingSpendability: .zero),
unshielded: .zero
)
@ -871,6 +876,11 @@ class CombineSynchronizerOfflineTests: XCTestCase {
spendableValue: Zatoshi(333),
changePendingConfirmation: .zero,
valuePendingSpendability: .zero),
orchardBalance:
PoolBalance(
spendableValue: Zatoshi(333),
changePendingConfirmation: .zero,
valuePendingSpendability: .zero),
unshielded: .zero
)

View File

@ -29,10 +29,13 @@ class SynchronizerOfflineTests: ZcashTestCase {
}
func testCallPrepareWithAlreadyUsedAliasThrowsError() async throws {
// Pick a testnet height for which both Sapling and Orchard are active.
let walletBirthday = 1900000
let firstTestCoordinator = try await TestCoordinator(
alias: .custom("alias"),
container: mockContainer,
walletBirthday: 10,
walletBirthday: walletBirthday,
network: network,
callPrepareInConstructor: false
)
@ -40,7 +43,7 @@ class SynchronizerOfflineTests: ZcashTestCase {
let secondTestCoordinator = try await TestCoordinator(
alias: .custom("alias"),
container: mockContainer,
walletBirthday: 10,
walletBirthday: walletBirthday,
network: network,
callPrepareInConstructor: false
)
@ -58,10 +61,13 @@ class SynchronizerOfflineTests: ZcashTestCase {
}
func testWhenSynchronizerIsDeallocatedAliasIsntUsedAnymore() async throws {
// Pick a testnet height for which both Sapling and Orchard are active.
let walletBirthday = 1900000
var testCoordinator: TestCoordinator! = try await TestCoordinator(
alias: .default,
container: mockContainer,
walletBirthday: 10,
walletBirthday: walletBirthday,
network: network,
callPrepareInConstructor: false
)
@ -75,7 +81,7 @@ class SynchronizerOfflineTests: ZcashTestCase {
testCoordinator = try await TestCoordinator(
alias: .default,
container: mockContainer,
walletBirthday: 10,
walletBirthday: walletBirthday,
network: network,
callPrepareInConstructor: false
)
@ -88,10 +94,13 @@ class SynchronizerOfflineTests: ZcashTestCase {
}
func testCallWipeWithAlreadyUsedAliasThrowsError() async throws {
// Pick a testnet height for which both Sapling and Orchard are active.
let walletBirthday = 1900000
let firstTestCoordinator = try await TestCoordinator(
alias: .default,
container: mockContainer,
walletBirthday: 10,
walletBirthday: walletBirthday,
network: network,
callPrepareInConstructor: false
)
@ -99,7 +108,7 @@ class SynchronizerOfflineTests: ZcashTestCase {
let secondTestCoordinator = try await TestCoordinator(
alias: .default,
container: mockContainer,
walletBirthday: 10,
walletBirthday: walletBirthday,
network: network,
callPrepareInConstructor: false
)
@ -146,10 +155,13 @@ class SynchronizerOfflineTests: ZcashTestCase {
}
func testPrepareCanBeCalledAfterWipeWithSameInstanceOfSDKSynchronizer() async throws {
// Pick a testnet height for which both Sapling and Orchard are active.
let walletBirthday = 1900000
let testCoordinator = try await TestCoordinator(
alias: .default,
container: mockContainer,
walletBirthday: 10,
walletBirthday: walletBirthday,
network: network,
callPrepareInConstructor: false
)
@ -180,10 +192,13 @@ class SynchronizerOfflineTests: ZcashTestCase {
}
func testSendToAddressCalledWithoutPrepareThrowsError() async throws {
// Pick a testnet height for which both Sapling and Orchard are active.
let walletBirthday = 1900000
let testCoordinator = try await TestCoordinator(
alias: .default,
container: mockContainer,
walletBirthday: 10,
walletBirthday: walletBirthday,
network: network,
callPrepareInConstructor: false
)
@ -205,10 +220,13 @@ class SynchronizerOfflineTests: ZcashTestCase {
}
func testShieldFundsCalledWithoutPrepareThrowsError() async throws {
// Pick a testnet height for which both Sapling and Orchard are active.
let walletBirthday = 1900000
let testCoordinator = try await TestCoordinator(
alias: .default,
container: mockContainer,
walletBirthday: 10,
walletBirthday: walletBirthday,
network: network,
callPrepareInConstructor: false
)
@ -229,10 +247,13 @@ class SynchronizerOfflineTests: ZcashTestCase {
}
func testRefreshUTXOCalledWithoutPrepareThrowsError() async throws {
// Pick a testnet height for which both Sapling and Orchard are active.
let walletBirthday = 1900000
let testCoordinator = try await TestCoordinator(
alias: .default,
container: mockContainer,
walletBirthday: 10,
walletBirthday: walletBirthday,
network: network,
callPrepareInConstructor: false
)
@ -249,10 +270,13 @@ class SynchronizerOfflineTests: ZcashTestCase {
}
func testRewindCalledWithoutPrepareThrowsError() async throws {
// Pick a testnet height for which both Sapling and Orchard are active.
let walletBirthday = 1900000
let testCoordinator = try await TestCoordinator(
alias: .default,
container: mockContainer,
walletBirthday: 10,
walletBirthday: walletBirthday,
network: network,
callPrepareInConstructor: false
)

View File

@ -32,7 +32,7 @@ final class UnifiedTypecodesTests: XCTestCase {
let typecodes = try DerivationTool(networkType: .testnet).receiverTypecodesFromUnifiedAddress(address)
XCTAssertEqual(typecodes, [.sapling, .p2pkh])
XCTAssertEqual(typecodes, [.orchard, .sapling, .p2pkh])
}
func testUnifiedAddressHasTransparentSaplingReceivers() throws {
@ -51,6 +51,7 @@ final class UnifiedTypecodesTests: XCTestCase {
XCTAssertEqual(
Set<UnifiedAddress.ReceiverTypecodes>(typecodes),
Set([
.orchard,
.sapling,
.p2pkh
])

View File

@ -126,6 +126,11 @@ class ZcashRustBackendTests: XCTestCase {
XCTFail("not enough transparent receivers")
return
}
// The first address in the wallet is created when the account is created, using
// the default receivers specified inside `zcash_client_sqlite`. The remaining
// addresses are generated here, using the receivers specified in the Swift SDK's
// FFI backend.
var uAddresses: [UnifiedAddress] = []
for i in 0...2 {
uAddresses.append(

View File

@ -190,6 +190,10 @@ class DarksideWalletService: LightWalletService {
func getSubtreeRoots(_ request: ZcashLightClientKit.GetSubtreeRootsArg) -> AsyncThrowingStream<ZcashLightClientKit.SubtreeRoot, Error> {
service.getSubtreeRoots(request)
}
func getTreeState(_ id: BlockID) async throws -> TreeState {
try await service.getTreeState(id)
}
}
enum DarksideWalletDConstants: NetworkConstants {

View File

@ -0,0 +1,35 @@
//
// TestingCheckpoints.swift
//
//
// Created by Francisco Gindre on 2023-10-31.
//
import Foundation
@testable import ZcashLightClientKit
struct DarksideMainnetCheckpointSource: CheckpointSource {
private let treeState = Checkpoint(
height: 663150,
hash: "0000000002fd3be4c24c437bd22620901617125ec2a3a6c902ec9a6c06f734fc",
time: 1576821833,
saplingTree: "01ec6278a1bed9e1b080fd60ef50eb17411645e3746ff129283712bc4757ecc833001001b4e1d4a26ac4a2810b57a14f4ffb69395f55dde5674ecd2462af96f9126e054701a36afb68534f640938bdffd80dfcb3f4d5e232488abbf67d049b33a761e7ed6901a16e35205fb7fe626a9b13fc43e1d2b98a9c241f99f93d5e93a735454073025401f5b9bcbf3d0e3c83f95ee79299e8aeadf30af07717bda15ffb7a3d00243b58570001fa6d4c2390e205f81d86b85ace0b48f3ce0afb78eeef3e14c70bcfd7c5f0191c0000011bc9521263584de20822f9483e7edb5af54150c4823c775b2efc6a1eded9625501a6030f8d4b588681eddb66cad63f09c5c7519db49500fc56ebd481ce5e903c22000163f4eec5a2fe00a5f45e71e1542ff01e937d2210c99f03addcce5314a5278b2d0163ab01f46a3bb6ea46f5a19d5bdd59eb3f81e19cfa6d10ab0fd5566c7a16992601fa6980c053d84f809b6abcf35690f03a11f87b28e3240828e32e3f57af41e54e01319312241b0031e3a255b0d708750b4cb3f3fe79e3503fe488cc8db1dd00753801754bb593ea42d231a7ddf367640f09bbf59dc00f2c1d2003cc340e0c016b5b13",
orchardTree: nil
)
var network: NetworkType {
DarksideWalletDNetwork().networkType
}
var saplingActivation: Checkpoint {
treeState
}
func latestKnownCheckpoint() -> Checkpoint {
treeState
}
func birthday(for height: BlockHeight) -> Checkpoint {
treeState
}
}

View File

@ -82,4 +82,8 @@ class MockLightWalletService: LightWalletService {
func getSubtreeRoots(_ request: ZcashLightClientKit.GetSubtreeRootsArg) -> AsyncThrowingStream<ZcashLightClientKit.SubtreeRoot, Error> {
service.getSubtreeRoots(request)
}
func getTreeState(_ id: BlockID) async throws -> TreeState {
try await service.getTreeState(id)
}
}

View File

@ -963,6 +963,30 @@ class LightWalletServiceMock: LightWalletService {
}
}
// MARK: - getTreeState
var getTreeStateThrowableError: Error?
var getTreeStateCallsCount = 0
var getTreeStateCalled: Bool {
return getTreeStateCallsCount > 0
}
var getTreeStateReceivedId: BlockID?
var getTreeStateReturnValue: TreeState!
var getTreeStateClosure: ((BlockID) async throws -> TreeState)?
func getTreeState(_ id: BlockID) async throws -> TreeState {
if let error = getTreeStateThrowableError {
throw error
}
getTreeStateCallsCount += 1
getTreeStateReceivedId = id
if let closure = getTreeStateClosure {
return try await closure(id)
} else {
return getTreeStateReturnValue
}
}
}
class LightWalletdInfoMock: LightWalletdInfo {
@ -1776,6 +1800,30 @@ class SynchronizerMock: Synchronizer {
try await switchToEndpointClosure!(endpoint)
}
// MARK: - isSeedRelevantToAnyDerivedAccount
var isSeedRelevantToAnyDerivedAccountSeedThrowableError: Error?
var isSeedRelevantToAnyDerivedAccountSeedCallsCount = 0
var isSeedRelevantToAnyDerivedAccountSeedCalled: Bool {
return isSeedRelevantToAnyDerivedAccountSeedCallsCount > 0
}
var isSeedRelevantToAnyDerivedAccountSeedReceivedSeed: [UInt8]?
var isSeedRelevantToAnyDerivedAccountSeedReturnValue: Bool!
var isSeedRelevantToAnyDerivedAccountSeedClosure: (([UInt8]) async throws -> Bool)?
func isSeedRelevantToAnyDerivedAccount(seed: [UInt8]) async throws -> Bool {
if let error = isSeedRelevantToAnyDerivedAccountSeedThrowableError {
throw error
}
isSeedRelevantToAnyDerivedAccountSeedCallsCount += 1
isSeedRelevantToAnyDerivedAccountSeedReceivedSeed = seed
if let closure = isSeedRelevantToAnyDerivedAccountSeedClosure {
return try await closure(seed)
} else {
return isSeedRelevantToAnyDerivedAccountSeedReturnValue
}
}
}
class TransactionRepositoryMock: TransactionRepository {
@ -2213,6 +2261,37 @@ actor ZcashRustBackendWeldingMock: ZcashRustBackendWelding {
self.consensusBranchIdForHeightClosure = consensusBranchIdForHeightClosure
}
// MARK: - listAccounts
var listAccountsThrowableError: Error?
func setListAccountsThrowableError(_ param: Error?) async {
listAccountsThrowableError = param
}
var listAccountsCallsCount = 0
var listAccountsCalled: Bool {
return listAccountsCallsCount > 0
}
var listAccountsReturnValue: [Int32]!
func setListAccountsReturnValue(_ param: [Int32]) async {
listAccountsReturnValue = param
}
var listAccountsClosure: (() async throws -> [Int32])?
func setListAccountsClosure(_ param: (() async throws -> [Int32])?) async {
listAccountsClosure = param
}
func listAccounts() async throws -> [Int32] {
if let error = listAccountsThrowableError {
throw error
}
listAccountsCallsCount += 1
if let closure = listAccountsClosure {
return try await closure()
} else {
return listAccountsReturnValue
}
}
// MARK: - createAccount
var createAccountSeedTreeStateRecoverUntilThrowableError: Error?
@ -2246,6 +2325,39 @@ actor ZcashRustBackendWeldingMock: ZcashRustBackendWelding {
}
}
// MARK: - isSeedRelevantToAnyDerivedAccount
var isSeedRelevantToAnyDerivedAccountSeedThrowableError: Error?
func setIsSeedRelevantToAnyDerivedAccountSeedThrowableError(_ param: Error?) async {
isSeedRelevantToAnyDerivedAccountSeedThrowableError = param
}
var isSeedRelevantToAnyDerivedAccountSeedCallsCount = 0
var isSeedRelevantToAnyDerivedAccountSeedCalled: Bool {
return isSeedRelevantToAnyDerivedAccountSeedCallsCount > 0
}
var isSeedRelevantToAnyDerivedAccountSeedReceivedSeed: [UInt8]?
var isSeedRelevantToAnyDerivedAccountSeedReturnValue: Bool!
func setIsSeedRelevantToAnyDerivedAccountSeedReturnValue(_ param: Bool) async {
isSeedRelevantToAnyDerivedAccountSeedReturnValue = param
}
var isSeedRelevantToAnyDerivedAccountSeedClosure: (([UInt8]) async throws -> Bool)?
func setIsSeedRelevantToAnyDerivedAccountSeedClosure(_ param: (([UInt8]) async throws -> Bool)?) async {
isSeedRelevantToAnyDerivedAccountSeedClosure = param
}
func isSeedRelevantToAnyDerivedAccount(seed: [UInt8]) async throws -> Bool {
if let error = isSeedRelevantToAnyDerivedAccountSeedThrowableError {
throw error
}
isSeedRelevantToAnyDerivedAccountSeedCallsCount += 1
isSeedRelevantToAnyDerivedAccountSeedReceivedSeed = seed
if let closure = isSeedRelevantToAnyDerivedAccountSeedClosure {
return try await closure(seed)
} else {
return isSeedRelevantToAnyDerivedAccountSeedReturnValue
}
}
// MARK: - decryptAndStoreTransaction
var decryptAndStoreTransactionTxBytesMinedHeightThrowableError: Error?
@ -2761,34 +2873,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
}
}

View File

@ -102,8 +102,8 @@ class RustBackendMockHelper {
try await rustBackend.suggestScanRanges()
}
await rustBackendMock.setScanBlocksFromHeightLimitClosure() { fromHeight, limit in
try await rustBackend.scanBlocks(fromHeight: fromHeight, limit: limit)
await rustBackendMock.setScanBlocksFromHeightFromStateLimitClosure { fromHeight, fromState, limit in
try await rustBackend.scanBlocks(fromHeight: fromHeight, fromState: fromState, limit: limit)
}
}
@ -145,7 +145,7 @@ extension SynchronizerState {
static var mock: SynchronizerState {
SynchronizerState(
syncSessionID: .nullID,
accountBalance: AccountBalance(saplingBalance: .zero, unshielded: Zatoshi(200)),
accountBalance: AccountBalance(saplingBalance: .zero, orchardBalance: .zero, unshielded: Zatoshi(200)),
internalSyncStatus: .syncing(0),
latestBlockHeight: 222222
)

View File

@ -63,6 +63,8 @@ enum TestDbBuilder {
case .success: return provider
case .seedRequired:
throw ZcashError.compactBlockProcessorDataDbInitFailed("Seed value required to initialize the wallet database")
case .seedNotRelevant:
throw ZcashError.compactBlockProcessorDataDbInitFailed("Relevant seed value required")
}
}

View File

@ -169,9 +169,9 @@ public let testVector: [[Any?]] =
[
["From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/unified_address.py"],
["p2pkh_bytes, p2sh_bytes, sapling_raw_addr, orchard_raw_addr, unknown_typecode, unknown_bytes, unified_addr, root_seed, account, diversifier_index"],
["7bb83570b8fae146e03c5331a020b1e0892f631d", nil, "d8ef8293d26de832e7193f296ba1922d90f122c6135bc231eebd91efdb03b1a8606771cd4fd6480574d43e", nil, nil, nil, "u1l8xunezsvhq8fgzfl7404m450nwnd76zshscn6nfys7vyz2ywyh4cc5daaq0c7q2su5lqfh23sp7fkf3kt27ve5948mzpfdvckzaect2jtte308mkwlycj2u0eac077wu70vqcetkxf", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0, 0],
["a7244a362f49f29644a955cf0039b88a61657861", nil, "435b0bbc95b5b7d52531a3944f2b85603ee22aaf850963bc156eb561edf2cbe7cf0e770e393ae5d7049026", nil, nil, nil, "u1fl5mprj0t9p4jg92hjjy8q5myvwc60c9wv0xachauqpn3c3k4xwzlaueafq27dcg7tzzzaz5jl8tyj93wgs983y0jq0qfhzu6n4r8rakpv5f4gg2lrw4z6pyqqcrcqx04d38yunc6je", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0, 3],
["e256dcb03e05dde7c91212b47a7461311c415059", nil, "69a25a38699708e5f6e76e54e6a7a2ab84dcf288df0d1f2563670168d6c44ace0ef11155c60d5c225e9dec", nil, nil, nil, "u1qxqf8ctkxlsdh7xdcgkdtyw4mku7dxma8tsz45xd6ttgs322gdk7kazg3sdn52z7na3tzcrzf7lt3xrdtfp9d4pccderalchvvxk8hghduxrky5guzqlw65fmgp6x7aj4k8v5jkgwuw", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0, 4],
["7bb83570b8fae146e03c5331a020b1e0892f631d", nil, "d8ef8293d26de832e7193f296ba1922d90f122c6135bc231eebd91efdb03b1a8606771cd4fd6480574d43e", nil, nil, nil, "u1m2p65qdnhexpfcmejjf6hjqd485xwfsrlf3cvc6wx5xhwrcq8myrdlqyhdpklz5d87ct0epfty0cr9d6q9fqtycx0j3vdhc2tzmkeejhtdqj3zrjqk3dd5ufpqkmueg89e6a6alvpaaxcx4fxsxqk4yj7g8dayn94d3afrsx66m3vq4rk03hc0ufmtkcm8wca7xja42f9kjau9708z7", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0, 0],
["a7244a362f49f29644a955cf0039b88a61657861", nil, "435b0bbc95b5b7d52531a3944f2b85603ee22aaf850963bc156eb561edf2cbe7cf0e770e393ae5d7049026", nil, nil, nil, "u196qfugjlzacex3pnhj5hgkj7ppjxeg3egcwkn364rnt59nx7p2f4pp35h4v677hla3negz4w0quy9ul6an2azqv0lt7f5n4dz5pspk0uvhkqfft4ntarat6mf0zfc46s5rsvmrd63lvnp2y8kyyes2r0k439de6je9ugy85qkq9ldc7hkkvjav69gzyfl5sen8kfxk3gyhjpzn39xj0", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0, 3],
["e256dcb03e05dde7c91212b47a7461311c415059", nil, "69a25a38699708e5f6e76e54e6a7a2ab84dcf288df0d1f2563670168d6c44ace0ef11155c60d5c225e9dec", nil, nil, nil, "u1vs0kanmdm4vtp2jy5lfsfspty0l7umph3ny6v9xwqpamvw2adshzsh24ukvc2hamwd8wky7sfalzv4szttsrss26m5yvxnh2r0h9u5vtksr0puhw89h7gm202h5qhn53cm2pt9uj7cwnymmgp26jxe9c0lt5z3egvl03hmdrg6r923t5xudetg2f6kzzn5h6xhaye8wmufnguaj8pws", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0, 4],
["cad268758c5e71493066446b98e71df9d1d6a5ca", nil, "9f6e0bf90a18fc0b9b83ae9f23ad4358648638482b5def8975635b66fd8a708335f9235a3186ec0f033f84", "cecbe5e689a453a3fe10ccf7617e6c1fb382819d7fc9200a1f42092ac84a30378f8c1fb90dff71a6d5042d", nil, nil, "u1pg2aaph7jp8rpf6yhsza25722sg5fcn3vaca6ze27hqjw7jvvhhuxkpcg0ge9xh6drsgdkda8qjq5chpehkcpxf87rnjryjqwymdheptpvnljqqrjqzjwkc2ma6hcq666kgwfytxwac8eyex6ndgr6ezte66706e3vaqrd25dzvzkc69kw0jgywtd0cmq52q5lkw6uh7hyvzjse8ksx", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 1, 3],
["8d653347a0fd3cd0842a790a5eaf89d8e3854659", nil, "e1adf156a07d56bcac91bdb2f7bb3ea7c44569dcfee54273c09e8065807b6823faa94a77219554d0f6e017", "24f8a60cbd97e012618d56054ad39241411a28fdd50ee35efa91152f60d5fa21172e5d458ddbcb6b709896", nil, nil, "u19mzuf4l37ny393m59v4mxx4t3uyxkh7qpqjdfvlfk9f504cv9w4fpl7cql0kqvssz8jay8mgl8lnrtvg6yzh9pranjj963acc3h2z2qt7007du0lsmdf862dyy40c3wmt0kq35k5z836tfljgzsqtdsccchayfjpygqzkx24l77ga3ngfgskqddyepz8we7ny4ggmt7q48cgvgu57mz", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 1, 7],
["e511f439b5f96cf824cd5e0e6b2eb8ee1bc83cb7", nil, "60ba572f8e379312d86897025decdd64b4b95e2c4afa9d13726b8cc393edb4988c51b976028f890f108bd2", "1f24294ed1b405c7b3b1c3f13db5b9b27b5d0f2aca9d589a69e5be00eb978621e6776e87ea326d47a34c1a", nil, nil, "u1mtxw5nras5glkxz093282sv3n2h8qs7cpxcmmaxj96vtzjzl6rmdaxs4e9es7mxwmd0h3k5wz3ce4ll5g4jz2pn9su4pufq74pxhp4t235n6j7aed3hh8ss7pf3sekf7apsf6vtg84ue5zcq2k9q3xv5yth3q50fu4czdm8sn8q4de3m5k76g2vwwyjsf50hqfxgmwxqxu0rsy22ktw", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 1, 8],