Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature branch for SDK 2.1.0 #1393

Merged
merged 10 commits into from
Mar 26, 2024
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,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"
}
}
],
Expand Down
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
],
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.1")
],
targets: [
.target(
Expand Down
31 changes: 9 additions & 22 deletions Sources/ZcashLightClientKit/Block/CompactBlockProcessor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ protocol UTXOFetcher {
}

struct UTXOFetcherImpl {
let accountRepository: AccountRepository
let blockDownloaderService: BlockDownloaderService
let config: UTXOFetcherConfig
let rustBackend: ZcashRustBackendWelding
Expand All @@ -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 {
Expand Down
5 changes: 4 additions & 1 deletion Sources/ZcashLightClientKit/Block/Scan/BlockScanner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
155 changes: 0 additions & 155 deletions Sources/ZcashLightClientKit/DAO/UnspentTransactionOutputDao.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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))
}
}
Loading
Loading