Merge pull request #603 from zcash/release/0.17.0-alpha.3
Release/0.17.0 alpha.3
This commit is contained in:
commit
d4a2a04d2b
|
@ -1,81 +1,13 @@
|
||||||
|
# 0.17.0-alpha.3
|
||||||
|
- [#602] Improve error logging for InitializerError and RustWeldingError
|
||||||
|
|
||||||
# 0.17.0-alpha.2
|
# 0.17.0-alpha.2
|
||||||
- [#579] Fix database lock
|
- [#579] Fix database lock
|
||||||
- [#592] Fix various tests and deleted some that are not useful anymore
|
- [#592] Fix various tests and deleted some that are not useful anymore
|
||||||
- [#581] getTransparentBalanceForAccount error not handled
|
- [#581] getTransparentBalanceForAccount error not handled
|
||||||
|
|
||||||
# 0.17.0-alpha.1
|
# 0.17.0-alpha.1
|
||||||
## Changes to Demo APP
|
See MIGRATING.md
|
||||||
The demo application now uses the SDKSynchronizer to create addresses and
|
|
||||||
shield funds.
|
|
||||||
`DerivationToolViewController` was removed. See `DerivationTool` unit tests
|
|
||||||
for sample code.
|
|
||||||
`GetAddressViewController` now derives transparent and sapling addresses
|
|
||||||
from Unified Address
|
|
||||||
`SendViewController` uses Unified Spending Key and type-safe `Memo`
|
|
||||||
|
|
||||||
## Changes To SDK
|
|
||||||
### `CompactBlockProcessor`
|
|
||||||
`public func getUnifiedAddress(accountIndex: Int) -> UnifiedAddress?`
|
|
||||||
`public func getSaplingAddress(accountIndex: Int) -> SaplingAddress?` derived from UA
|
|
||||||
`public func getTransparentAddress(accountIndex: Int) -> TransparentAddress?`
|
|
||||||
is derived from UA
|
|
||||||
`public func getTransparentBalance(accountIndex: Int) throws -> WalletBalance` now
|
|
||||||
fetches from account exclusively
|
|
||||||
`func refreshUTXOs(tAddress: TransparentAddress, startHeight: BlockHeight) async throws -> RefreshedUTXOs`
|
|
||||||
uses `TransparentAddress`
|
|
||||||
|
|
||||||
### Initializer
|
|
||||||
Migration of DataDB and CacheDB are delegated to `librustzcash`
|
|
||||||
|
|
||||||
removed `public func getAddress(index account: Int = 0) -> String`
|
|
||||||
|
|
||||||
|
|
||||||
### Wallet Types
|
|
||||||
`UnifiedSpendingKey` to represent Unified Spending Keys. This is a binary
|
|
||||||
encoded not meant to be stored or backed up. This only serves the purpuse
|
|
||||||
of letting clients use the least priviledge keys at all times for every
|
|
||||||
operation.
|
|
||||||
|
|
||||||
### Synchronizer
|
|
||||||
`sendToAddress` and `shieldFunds` now take a `UnifiedSpendingKey` instead
|
|
||||||
of the respective spending and transparent private keys.
|
|
||||||
`refreshUTXOs` uses `TransparentAddress`
|
|
||||||
|
|
||||||
### KeyDeriving protocol
|
|
||||||
Addresses should be obtained from the `Synchronizer` by using the `get_address` functions
|
|
||||||
Transparent and Sapling receivers should be obtained by extracting the receivers of a UA
|
|
||||||
````Swift
|
|
||||||
public extension UnifiedAddress {
|
|
||||||
/// Extracts the sapling receiver from this UA if available
|
|
||||||
/// - Returns: an `Optional<SaplingAddress>`
|
|
||||||
func saplingReceiver() -> SaplingAddress? {
|
|
||||||
try? DerivationTool.saplingReceiver(from: self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extracts the transparent receiver from this UA if available
|
|
||||||
/// - Returns: an `Optional<TransparentAddress>`
|
|
||||||
func transparentReceiver() -> TransparentAddress? {
|
|
||||||
try? DerivationTool.transparentReceiver(from: self)
|
|
||||||
}
|
|
||||||
````
|
|
||||||
|
|
||||||
**Removed**
|
|
||||||
`func deriveUnifiedFullViewingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [UnifiedFullViewingKey]`
|
|
||||||
`func deriveViewingKey(spendingKey: SaplingExtendedSpendingKey) throws -> SaplingExtendedFullViewingKey`
|
|
||||||
`func deriveSpendingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [SaplingExtendedSpendingKey]`
|
|
||||||
`func deriveUnifiedAddress(from ufvk: UnifiedFullViewingKey) throws -> UnifiedAddress`
|
|
||||||
`func deriveTransparentAddress(seed: [UInt8], account: Int, index: Int) throws -> TransparentAddress`
|
|
||||||
`func deriveTransparentAccountPrivateKey(seed: [UInt8], account: Int) throws -> TransparentAccountPrivKey`
|
|
||||||
`func deriveTransparentAddressFromAccountPrivateKey(_ xprv: TransparentAccountPrivKey, index: Int) throws -> TransparentAddress`
|
|
||||||
|
|
||||||
**Added**
|
|
||||||
`static func saplingReceiver(from unifiedAddress: UnifiedAddress) throws -> SaplingAddress?`
|
|
||||||
`static func transparentReceiver(from unifiedAddress: UnifiedAddress) throws -> TransparentAddress?`
|
|
||||||
`static func receiverTypecodesFromUnifiedAddress(_ address: UnifiedAddress) throws -> [UnifiedAddress.ReceiverTypecodes]`
|
|
||||||
`func deriveUnifiedSpendingKey(seed: [UInt8], accountIndex: Int) throws -> UnifiedSpendingKey`
|
|
||||||
`public func deriveUnifiedFullViewingKey(from spendingKey: UnifiedSpendingKey) throws -> UnifiedFullViewingKey`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 0.16-13-beta
|
# 0.16-13-beta
|
||||||
- [#597] SDK does not build with SQLite 0.14
|
- [#597] SDK does not build with SQLite 0.14
|
|
@ -0,0 +1,74 @@
|
||||||
|
# Migrating from 0.16.x-beta to 0.17.0-alpha.x
|
||||||
|
|
||||||
|
## Changes to Demo APP
|
||||||
|
The demo application now uses the SDKSynchronizer to create addresses and
|
||||||
|
shield funds.
|
||||||
|
`DerivationToolViewController` was removed. See `DerivationTool` unit tests
|
||||||
|
for sample code.
|
||||||
|
`GetAddressViewController` now derives transparent and sapling addresses
|
||||||
|
from Unified Address
|
||||||
|
`SendViewController` uses Unified Spending Key and type-safe `Memo`
|
||||||
|
|
||||||
|
## Changes To SDK
|
||||||
|
### `CompactBlockProcessor`
|
||||||
|
`public func getUnifiedAddress(accountIndex: Int) -> UnifiedAddress?`
|
||||||
|
`public func getSaplingAddress(accountIndex: Int) -> SaplingAddress?` derived from UA
|
||||||
|
`public func getTransparentAddress(accountIndex: Int) -> TransparentAddress?`
|
||||||
|
is derived from UA
|
||||||
|
`public func getTransparentBalance(accountIndex: Int) throws -> WalletBalance` now
|
||||||
|
fetches from account exclusively
|
||||||
|
`func refreshUTXOs(tAddress: TransparentAddress, startHeight: BlockHeight) async throws -> RefreshedUTXOs`
|
||||||
|
uses `TransparentAddress`
|
||||||
|
|
||||||
|
### Initializer
|
||||||
|
Migration of DataDB and CacheDB are delegated to `librustzcash`
|
||||||
|
|
||||||
|
removed `public func getAddress(index account: Int = 0) -> String`
|
||||||
|
|
||||||
|
|
||||||
|
### Wallet Types
|
||||||
|
`UnifiedSpendingKey` to represent Unified Spending Keys. This is a binary
|
||||||
|
encoded not meant to be stored or backed up. This only serves the purpuse
|
||||||
|
of letting clients use the least priviledge keys at all times for every
|
||||||
|
operation.
|
||||||
|
|
||||||
|
### Synchronizer
|
||||||
|
`sendToAddress` and `shieldFunds` now take a `UnifiedSpendingKey` instead
|
||||||
|
of the respective spending and transparent private keys.
|
||||||
|
`refreshUTXOs` uses `TransparentAddress`
|
||||||
|
|
||||||
|
### KeyDeriving protocol
|
||||||
|
Addresses should be obtained from the `Synchronizer` by using the `get_address` functions
|
||||||
|
Transparent and Sapling receivers should be obtained by extracting the receivers of a UA
|
||||||
|
````Swift
|
||||||
|
public extension UnifiedAddress {
|
||||||
|
/// Extracts the sapling receiver from this UA if available
|
||||||
|
/// - Returns: an `Optional<SaplingAddress>`
|
||||||
|
func saplingReceiver() -> SaplingAddress? {
|
||||||
|
try? DerivationTool.saplingReceiver(from: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the transparent receiver from this UA if available
|
||||||
|
/// - Returns: an `Optional<TransparentAddress>`
|
||||||
|
func transparentReceiver() -> TransparentAddress? {
|
||||||
|
try? DerivationTool.transparentReceiver(from: self)
|
||||||
|
}
|
||||||
|
````
|
||||||
|
|
||||||
|
**Removed**
|
||||||
|
`func deriveUnifiedFullViewingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [UnifiedFullViewingKey]`
|
||||||
|
`func deriveViewingKey(spendingKey: SaplingExtendedSpendingKey) throws -> SaplingExtendedFullViewingKey`
|
||||||
|
`func deriveSpendingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [SaplingExtendedSpendingKey]`
|
||||||
|
`func deriveUnifiedAddress(from ufvk: UnifiedFullViewingKey) throws -> UnifiedAddress`
|
||||||
|
`func deriveTransparentAddress(seed: [UInt8], account: Int, index: Int) throws -> TransparentAddress`
|
||||||
|
`func deriveTransparentAccountPrivateKey(seed: [UInt8], account: Int) throws -> TransparentAccountPrivKey`
|
||||||
|
`func deriveTransparentAddressFromAccountPrivateKey(_ xprv: TransparentAccountPrivKey, index: Int) throws -> TransparentAddress`
|
||||||
|
|
||||||
|
**Added**
|
||||||
|
`static func saplingReceiver(from unifiedAddress: UnifiedAddress) throws -> SaplingAddress?`
|
||||||
|
`static func transparentReceiver(from unifiedAddress: UnifiedAddress) throws -> TransparentAddress?`
|
||||||
|
`static func receiverTypecodesFromUnifiedAddress(_ address: UnifiedAddress) throws -> [UnifiedAddress.ReceiverTypecodes]`
|
||||||
|
`func deriveUnifiedSpendingKey(seed: [UInt8], accountIndex: Int) throws -> UnifiedSpendingKey`
|
||||||
|
`public func deriveUnifiedFullViewingKey(from spendingKey: UnifiedSpendingKey) throws -> UnifiedFullViewingKey`
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,9 @@ Wrapper for the Rust backend. This class basically represents all the Rust-walle
|
||||||
capabilities and the supporting data required to exercise those abilities.
|
capabilities and the supporting data required to exercise those abilities.
|
||||||
*/
|
*/
|
||||||
public enum InitializerError: Error {
|
public enum InitializerError: Error {
|
||||||
case cacheDbInitFailed
|
case cacheDbInitFailed(Error)
|
||||||
case dataDbInitFailed
|
case dataDbInitFailed(Error)
|
||||||
case accountInitFailed
|
case accountInitFailed(Error)
|
||||||
case falseStart
|
|
||||||
case invalidViewingKey(key: String)
|
case invalidViewingKey(key: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +196,7 @@ public class Initializer {
|
||||||
do {
|
do {
|
||||||
try storage.createTable()
|
try storage.createTable()
|
||||||
} catch {
|
} catch {
|
||||||
throw InitializerError.cacheDbInitFailed
|
throw InitializerError.cacheDbInitFailed(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -205,7 +204,7 @@ public class Initializer {
|
||||||
return .seedRequired
|
return .seedRequired
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
throw InitializerError.dataDbInitFailed
|
throw InitializerError.dataDbInitFailed(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
let checkpoint = Checkpoint.birthday(with: self.walletBirthday, network: network)
|
let checkpoint = Checkpoint.birthday(with: self.walletBirthday, network: network)
|
||||||
|
@ -221,7 +220,7 @@ public class Initializer {
|
||||||
} catch RustWeldingError.dataDbNotEmpty {
|
} catch RustWeldingError.dataDbNotEmpty {
|
||||||
// this is fine
|
// this is fine
|
||||||
} catch {
|
} catch {
|
||||||
throw InitializerError.dataDbInitFailed
|
throw InitializerError.dataDbInitFailed(error)
|
||||||
}
|
}
|
||||||
self.walletBirthday = checkpoint.height
|
self.walletBirthday = checkpoint.height
|
||||||
|
|
||||||
|
@ -230,19 +229,17 @@ public class Initializer {
|
||||||
lowerBoundHeight = max(walletBirthday, lastDownloaded)
|
lowerBoundHeight = max(walletBirthday, lastDownloaded)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
guard try rustBackend.initAccountsTable(
|
try rustBackend.initAccountsTable(
|
||||||
dbData: dataDbURL,
|
dbData: dataDbURL,
|
||||||
ufvks: viewingKeys,
|
ufvks: viewingKeys,
|
||||||
networkType: network.networkType
|
networkType: network.networkType
|
||||||
) else {
|
)
|
||||||
throw rustBackend.lastError() ?? InitializerError.accountInitFailed
|
|
||||||
}
|
|
||||||
} catch RustWeldingError.dataDbNotEmpty {
|
} catch RustWeldingError.dataDbNotEmpty {
|
||||||
// this is fine
|
// this is fine
|
||||||
} catch RustWeldingError.malformedStringInput {
|
} catch RustWeldingError.malformedStringInput {
|
||||||
throw RustWeldingError.malformedStringInput
|
throw RustWeldingError.malformedStringInput
|
||||||
} catch {
|
} catch {
|
||||||
throw rustBackend.lastError() ?? InitializerError.accountInitFailed
|
throw InitializerError.accountInitFailed(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
let migrationManager = MigrationManager(
|
let migrationManager = MigrationManager(
|
||||||
|
@ -371,3 +368,19 @@ enum CompactBlockProcessorBuilder {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension InitializerError: LocalizedError {
|
||||||
|
public var errorDescription: String? {
|
||||||
|
switch self {
|
||||||
|
case .invalidViewingKey:
|
||||||
|
return "The provided viewing key is invalid"
|
||||||
|
case .cacheDbInitFailed(let error):
|
||||||
|
return "cacheDb Init failed with error: \(error.localizedDescription)"
|
||||||
|
case .dataDbInitFailed(let error):
|
||||||
|
return "dataDb init failed with error: \(error.localizedDescription)"
|
||||||
|
case .accountInitFailed(let error):
|
||||||
|
return "account table init failed with error: \(error.localizedDescription)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -434,7 +434,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
dbData: URL,
|
dbData: URL,
|
||||||
ufvks: [UnifiedFullViewingKey],
|
ufvks: [UnifiedFullViewingKey],
|
||||||
networkType: NetworkType
|
networkType: NetworkType
|
||||||
) throws -> Bool {
|
) throws {
|
||||||
let dbData = dbData.osStr()
|
let dbData = dbData.osStr()
|
||||||
|
|
||||||
var ffiUfvks = [FFIEncodedKey]()
|
var ffiUfvks = [FFIEncodedKey]()
|
||||||
|
@ -477,7 +477,9 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
guard result else {
|
||||||
|
throw lastError() ?? .genericError(message: "`initAccountsTable` failed with unknown error")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// swiftlint:disable function_parameter_count
|
// swiftlint:disable function_parameter_count
|
||||||
|
@ -730,3 +732,28 @@ extension UnsafeMutablePointer where Pointee == UInt8 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension RustWeldingError: LocalizedError {
|
||||||
|
var errorDescription: String? {
|
||||||
|
switch self {
|
||||||
|
case .genericError(let message):
|
||||||
|
return "RustWeldingError generic error: \(message)"
|
||||||
|
case .dataDbInitFailed(let message):
|
||||||
|
return "`RustWeldingError.dataDbInitFailed` with message: \(message)"
|
||||||
|
case .dataDbNotEmpty:
|
||||||
|
return "`.DataDbNotEmpty`. This is usually not an error."
|
||||||
|
case .invalidInput(let message):
|
||||||
|
return "`RustWeldingError.invalidInput` with message: \(message)"
|
||||||
|
case .malformedStringInput:
|
||||||
|
return "`.malformedStringInput` Called a function with a malformed string input."
|
||||||
|
case .invalidRewind:
|
||||||
|
return "`.invalidRewind` called the rewind API with an arbitrary height that is not valid."
|
||||||
|
case .noConsensusBranchId(let branchId):
|
||||||
|
return "`.noConsensusBranchId` number \(branchId)"
|
||||||
|
case .saplingSpendParametersNotFound:
|
||||||
|
return "`.saplingSpendParametersNotFound` sapling parameters not present at specified URL"
|
||||||
|
case .unableToDeriveKeys:
|
||||||
|
return "`.unableToDeriveKeys` the requested keys could not be derived from the source provided"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -245,7 +245,7 @@ protocol ZcashRustBackendWelding {
|
||||||
dbData: URL,
|
dbData: URL,
|
||||||
ufvks: [UnifiedFullViewingKey],
|
ufvks: [UnifiedFullViewingKey],
|
||||||
networkType: NetworkType
|
networkType: NetworkType
|
||||||
) throws -> Bool
|
) throws
|
||||||
|
|
||||||
/// initializes the data db. This will performs any migrations needed on the sqlite file
|
/// initializes the data db. This will performs any migrations needed on the sqlite file
|
||||||
/// provided. Some migrations might need that callers provide the seed bytes.
|
/// provided. Some migrations might need that callers provide the seed bytes.
|
||||||
|
|
|
@ -74,11 +74,13 @@ class TransactionEnhancementTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
guard try rustBackend.initAccountsTable(
|
do {
|
||||||
|
try rustBackend.initAccountsTable(
|
||||||
dbData: processorConfig.dataDb,
|
dbData: processorConfig.dataDb,
|
||||||
ufvks: ufvks,
|
ufvks: ufvks,
|
||||||
networkType: network.networkType
|
networkType: network.networkType
|
||||||
) else {
|
)
|
||||||
|
} catch {
|
||||||
XCTFail("Failed to init accounts table error: " + String(describing: rustBackend.getLastError()))
|
XCTFail("Failed to init accounts table error: " + String(describing: rustBackend.getLastError()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,11 +131,13 @@ class BlockScanTests: XCTestCase {
|
||||||
.map { try derivationTool.deriveUnifiedFullViewingKey(from: $0) }
|
.map { try derivationTool.deriveUnifiedFullViewingKey(from: $0) }
|
||||||
|
|
||||||
|
|
||||||
guard try self.rustWelding.initAccountsTable(
|
do {
|
||||||
|
try self.rustWelding.initAccountsTable(
|
||||||
dbData: self.dataDbURL,
|
dbData: self.dataDbURL,
|
||||||
ufvks: [ufvk],
|
ufvks: [ufvk],
|
||||||
networkType: network.networkType
|
networkType: network.networkType
|
||||||
) else {
|
)
|
||||||
|
} catch {
|
||||||
XCTFail("failed to init account table. error: \(self.rustWelding.getLastError() ?? "no error found")")
|
XCTFail("failed to init account table. error: \(self.rustWelding.getLastError() ?? "no error found")")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,10 +71,13 @@ class ZcashRustBackendTests: XCTestCase {
|
||||||
.deriveFullViewingKey()
|
.deriveFullViewingKey()
|
||||||
|
|
||||||
]
|
]
|
||||||
guard try ZcashRustBackend.initAccountsTable(dbData: dbData!, ufvks: ufvks, networkType: networkType) else {
|
do {
|
||||||
|
try ZcashRustBackend.initAccountsTable(dbData: dbData!, ufvks: ufvks, networkType: networkType)
|
||||||
|
} catch {
|
||||||
XCTFail("failed with error: \(String(describing: ZcashRustBackend.lastError()))")
|
XCTFail("failed with error: \(String(describing: ZcashRustBackend.lastError()))")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
XCTAssertNotNil(
|
XCTAssertNotNil(
|
||||||
try ZcashRustBackend.createAccount(
|
try ZcashRustBackend.createAccount(
|
||||||
dbData: dbData!,
|
dbData: dbData!,
|
||||||
|
|
|
@ -55,6 +55,10 @@ extension LightWalletServiceMockResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockRustBackend: ZcashRustBackendWelding {
|
class MockRustBackend: ZcashRustBackendWelding {
|
||||||
|
static func initAccountsTable(dbData: URL, ufvks: [ZcashLightClientKit.UnifiedFullViewingKey], networkType: ZcashLightClientKit.NetworkType) throws {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static func createToAddress(dbData: URL, usk: ZcashLightClientKit.UnifiedSpendingKey, to address: String, value: Int64, memo: ZcashLightClientKit.MemoBytes?, spendParamsPath: String, outputParamsPath: String, networkType: ZcashLightClientKit.NetworkType) -> Int64 {
|
static func createToAddress(dbData: URL, usk: ZcashLightClientKit.UnifiedSpendingKey, to address: String, value: Int64, memo: ZcashLightClientKit.MemoBytes?, spendParamsPath: String, outputParamsPath: String, networkType: ZcashLightClientKit.NetworkType) -> Int64 {
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
Pod::Spec.new do |s|
|
Pod::Spec.new do |s|
|
||||||
s.name = 'ZcashLightClientKit'
|
s.name = 'ZcashLightClientKit'
|
||||||
s.version = '0.17.0-alpha.2'
|
s.version = '0.17.0-alpha.3'
|
||||||
s.summary = 'Zcash Light Client wallet SDK for iOS'
|
s.summary = 'Zcash Light Client wallet SDK for iOS'
|
||||||
|
|
||||||
s.description = <<-DESC
|
s.description = <<-DESC
|
||||||
|
|
Loading…
Reference in New Issue