Merge pull request #291 from zcash/network-agnostic-build

Network agnostic build
This commit is contained in:
Francisco Gindre 2021-07-30 10:40:55 -03:00 committed by GitHub
commit 7f41511855
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
78 changed files with 2315 additions and 1105 deletions

View File

@ -1,6 +1,6 @@
language: swift language: swift
os: osx os: osx
osx_image: xcode12.2 osx_image: xcode12.5
xcode_workspace: ./Example/ZcashLightClientSample/ZcashLightClientSample.xcworkspace xcode_workspace: ./Example/ZcashLightClientSample/ZcashLightClientSample.xcworkspace
xcode_scheme: ZcashLightClientSample xcode_scheme: ZcashLightClientSample
xcode_destination: platform=iOS Simulator,OS=14.2,name=iPhone 8 xcode_destination: platform=iOS Simulator,OS=14.2,name=iPhone 8
@ -9,9 +9,6 @@ addons:
packages: packages:
- rustup-init - rustup-init
- sourcery - sourcery
env:
global:
- ZCASH_NETWORK_ENVIRONMENT: TESTNET
install: install:
- ${TRAVIS_BUILD_DIR}/Scripts/travis/rust_setup.sh - ${TRAVIS_BUILD_DIR}/Scripts/travis/rust_setup.sh
- ${TRAVIS_BUILD_DIR}/Scripts/travis/ZcashLightClientSample_setup.sh - ${TRAVIS_BUILD_DIR}/Scripts/travis/ZcashLightClientSample_setup.sh
@ -19,4 +16,4 @@ install:
- curl https://z.cash/downloads/sapling-output.params > ${TRAVIS_BUILD_DIR}/ZcashLightClientKitTests/sapling-spend.params - curl https://z.cash/downloads/sapling-output.params > ${TRAVIS_BUILD_DIR}/ZcashLightClientKitTests/sapling-spend.params
script: script:
- swiftlint - swiftlint
- travis_wait 60 xcodebuild -quiet -UseModernBuildSystem=NO -workspace ./Example/ZcashLightClientSample/ZcashLightClientSample.xcworkspace -scheme ZcashLightClientSample -destination platform\=iOS\ Simulator,OS\=14.2,name\=iPhone\ 8 build - travis_wait 60 xcodebuild -quiet -UseModernBuildSystem=NO -workspace ./Example/ZcashLightClientSample/ZcashLightClientSample.xcworkspace -scheme ZcashLightClientSample -destination platform\=iOS\ Simulator,OS\=14.5,name\=iPhone\ 8 build

2
Cargo.lock generated
View File

@ -703,7 +703,7 @@ dependencies = [
[[package]] [[package]]
name = "libzcashlc" name = "libzcashlc"
version = "0.0.6" version = "0.0.7"
dependencies = [ dependencies = [
"base58", "base58",
"bitvec 0.18.5", "bitvec 0.18.5",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libzcashlc" name = "libzcashlc"
version = "0.0.6" version = "0.0.7"
authors = ["Jack Grigg <jack@z.cash>", authors = ["Jack Grigg <jack@z.cash>",
"Francisco Gindre <francisco@z.cash>", "Francisco Gindre <francisco@z.cash>",
] ]
@ -50,5 +50,5 @@ zcash_primitives = {git = "https://github.com/nuttycom/librustzcash", branch = "
zcash_proofs = {git = "https://github.com/nuttycom/librustzcash", branch = "autoshield-poc-daa" } zcash_proofs = {git = "https://github.com/nuttycom/librustzcash", branch = "autoshield-poc-daa" }
[features] [features]
mainnet = ["zcash_client_sqlite/mainnet", "zcash_client_backend/transparent-inputs", "zcash_primitives/transparent-inputs"] mainnet = ["zcash_client_sqlite/mainnet"]
testnet = ["zcash_client_backend/transparent-inputs", "zcash_primitives/transparent-inputs"] testnet = []

View File

@ -0,0 +1,99 @@
//
// DerivatioToolTestnetTests.swift
// ZcashLightClientKit-Unit-DerivationToolTests
//
// Created by Francisco Gindre on 7/26/21.
//
// swift-format-ignore-file
import XCTest
@testable import ZcashLightClientKit
class DerivatioToolTestnetTests: XCTestCase {
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment?
var seedData: Data = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")!
let testRecipientAddress = "ztestsapling1475xtm56czrzmleqzzlu4cxvjjfsy2p6rv78q07232cpsx5ee52k0mn5jyndq09mampkgvrxnwg" //TODO: Parameterize this from environment
let expectedSpendingKey = "secret-extended-key-test1qdxykmuaqqqqpqqg3x5c02p4rhw0rtszr8ln4xl7g6wg6qzsqgn445qsu3cq4vd6lk8xce3d4jw7s8ln5yjp6fqv2g0nzue2hc0kv5t004vklvlenncscq9flwh5vf5qnv0hnync72n7gjn70u47765v3kyrxytx50g730svvmhhlazn5rj8mshh470fkrmzg4xarhrqlygg8f486307ujhndwhsw2h7ddzf89k3534aeu0ypz2tjgrzlcqtat380vhe8awm03f58cqe49swv"
let expectedViewingKey = "zxviewtestsapling1qdxykmuaqqqqpqqg3x5c02p4rhw0rtszr8ln4xl7g6wg6qzsqgn445qsu3cq4vd6l5smlqrckkl2x5rnrauzc4gp665q3zyw0qf2sfdsx5wpp832htfavqk72uchuuvq2dpmgk8jfaza5t5l56u66fpx0sr8ewp9s3wj2txavmhhlazn5rj8mshh470fkrmzg4xarhrqlygg8f486307ujhndwhsw2h7ddzf89k3534aeu0ypz2tjgrzlcqtat380vhe8awm03f58cqgegsaj"
let derivationTool = DerivationTool(networkType: NetworkType.testnet)
let expectedTransparentAddress = "tmXuTnE11JojToagTqxXUn6KvdxDE3iLKbp"
func testDeriveViewingKeysFromSeed() throws {
let accounts: Int = 1
let seedBytes = [UInt8](seedData)
let viewingKeys = try derivationTool.deriveViewingKeys(seed: seedBytes, numberOfAccounts: accounts)
XCTAssertEqual(viewingKeys.count, accounts, "the number of viewing keys have to match the number of account requested to derive")
guard let viewingKey = viewingKeys.first else {
XCTFail("no viewing key generated")
return
}
XCTAssertEqual(expectedViewingKey, viewingKey)
}
func testDeriveViewingKeyFromSpendingKeys() throws {
XCTAssertEqual(expectedViewingKey, try derivationTool.deriveViewingKey(spendingKey: expectedSpendingKey))
}
func testDeriveSpendingKeysFromSeed() throws {
let accounts: Int = 1
let seedBytes = [UInt8](seedData)
let spendingKeys = try derivationTool.deriveSpendingKeys(seed: seedBytes, numberOfAccounts: accounts)
XCTAssertEqual(spendingKeys.count, accounts, "the number of viewing keys have to match the number of account requested to derive")
guard let spendingKey = spendingKeys.first else {
XCTFail("no viewing key generated")
return
}
XCTAssertEqual(expectedSpendingKey, spendingKey)
}
func testDeriveShieldedAddressFromSeed() throws {
let seedBytes = [UInt8](seedData)
let shieldedAddress = try derivationTool.deriveShieldedAddress(seed: seedBytes, accountIndex: 0)
XCTAssertEqual(shieldedAddress, testRecipientAddress)
}
func testDeriveShieldedAddressFromViewingKey() throws {
XCTAssertEqual(try derivationTool.deriveShieldedAddress(viewingKey: expectedViewingKey), testRecipientAddress)
}
func testDeriveTransparentAddressFromSeed() throws {
XCTAssertEqual(try derivationTool.deriveTransparentAddress(seed: [UInt8](seedData)), expectedTransparentAddress)
}
func testIsValidViewingKey() throws {
XCTAssertTrue(try derivationTool.isValidExtendedViewingKey(self.expectedViewingKey))
XCTAssertFalse(try derivationTool.isValidExtendedViewingKey("zxviews1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkysswfhjk79n8l99f2grd26dqg6dy3jcmxsaypxfsu6ara6vsk3x8l544uaksstx9zre879mdg7s9a7zurrx6pf5qg2n323js2s3zlu8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszcq7kwxy"))
}
func testDeriveSecretKeyFromSeed() throws {
XCTAssertEqual(try derivationTool.deriveTransparentPrivateKey(seed: [UInt8](seedData)), "L2BCTxmSDiBRb33kGFd4pwGhp9r3FZqG3LZihgTkkg1J14vwtDbq")
}
func testDeriveUnifiedKeysFromSeed() throws {
let unifiedKeys = try derivationTool.deriveUnifiedViewingKeysFromSeed([UInt8](seedData), numberOfAccounts: 1)
XCTAssertEqual(unifiedKeys.count, 1)
XCTAssertEqual(unifiedKeys[0].extfvk, expectedViewingKey)
XCTAssertEqual(expectedTransparentAddress, try derivationTool.deriveTransparentAddressFromPublicKey(unifiedKeys[0].extpub))
}
func testDeriveQuiteALotOfUnifiedKeysFromSeed() throws {
let unifiedKeys = try derivationTool.deriveUnifiedViewingKeysFromSeed([UInt8](seedData), numberOfAccounts: 10)
XCTAssertEqual(unifiedKeys.count, 10)
XCTAssertEqual(unifiedKeys[0].extfvk, expectedViewingKey)
XCTAssertEqual(expectedTransparentAddress, try derivationTool.deriveTransparentAddressFromPublicKey(unifiedKeys[0].extpub))
}
}

View File

@ -8,7 +8,7 @@
import XCTest import XCTest
import ZcashLightClientKit import ZcashLightClientKit
class DerivationToolTests: XCTestCase { class DerivationToolMainnetTests: XCTestCase {
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment? var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment?
var seedData: Data = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")! var seedData: Data = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")!
let testRecipientAddress = "zs1vp7kvlqr4n9gpehztr76lcn6skkss9p8keqs3nv8avkdtjrcctrvmk9a7u494kluv756jeee5k0" //TODO: Parameterize this from environment let testRecipientAddress = "zs1vp7kvlqr4n9gpehztr76lcn6skkss9p8keqs3nv8avkdtjrcctrvmk9a7u494kluv756jeee5k0" //TODO: Parameterize this from environment
@ -17,11 +17,12 @@ class DerivationToolTests: XCTestCase {
let expectedViewingKey = "zxviews1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkysswfhjk79n8l99f2grd26dqg6dy3jcmxsaypxfsu6ara6vsk3x8l544uaksstx9zre879mdg7s9a7zurrx6pf5qg2n323js2s3zlu8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszcq7kwxy" let expectedViewingKey = "zxviews1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkysswfhjk79n8l99f2grd26dqg6dy3jcmxsaypxfsu6ara6vsk3x8l544uaksstx9zre879mdg7s9a7zurrx6pf5qg2n323js2s3zlu8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszcq7kwxy"
let derivationTool = DerivationTool(networkType: NetworkType.mainnet)
let expectedTransparentAddress = "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz" let expectedTransparentAddress = "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz"
func testDeriveViewingKeysFromSeed() throws { func testDeriveViewingKeysFromSeed() throws {
let accounts: Int = 1 let accounts: Int = 1
let seedBytes = [UInt8](seedData) let seedBytes = [UInt8](seedData)
let viewingKeys = try DerivationTool.default.deriveViewingKeys(seed: seedBytes, numberOfAccounts: accounts) let viewingKeys = try derivationTool.deriveViewingKeys(seed: seedBytes, numberOfAccounts: accounts)
XCTAssertEqual(viewingKeys.count, accounts, "the number of viewing keys have to match the number of account requested to derive") XCTAssertEqual(viewingKeys.count, accounts, "the number of viewing keys have to match the number of account requested to derive")
@ -34,14 +35,14 @@ class DerivationToolTests: XCTestCase {
} }
func testDeriveViewingKeyFromSpendingKeys() throws { func testDeriveViewingKeyFromSpendingKeys() throws {
XCTAssertEqual(expectedViewingKey, try DerivationTool.default.deriveViewingKey(spendingKey: expectedSpendingKey)) XCTAssertEqual(expectedViewingKey, try derivationTool.deriveViewingKey(spendingKey: expectedSpendingKey))
} }
func testDeriveSpendingKeysFromSeed() throws { func testDeriveSpendingKeysFromSeed() throws {
let accounts: Int = 1 let accounts: Int = 1
let seedBytes = [UInt8](seedData) let seedBytes = [UInt8](seedData)
let spendingKeys = try DerivationTool.default.deriveSpendingKeys(seed: seedBytes, numberOfAccounts: accounts) let spendingKeys = try derivationTool.deriveSpendingKeys(seed: seedBytes, numberOfAccounts: accounts)
XCTAssertEqual(spendingKeys.count, accounts, "the number of viewing keys have to match the number of account requested to derive") XCTAssertEqual(spendingKeys.count, accounts, "the number of viewing keys have to match the number of account requested to derive")
guard let spendingKey = spendingKeys.first else { guard let spendingKey = spendingKeys.first else {
@ -55,44 +56,44 @@ class DerivationToolTests: XCTestCase {
func testDeriveShieldedAddressFromSeed() throws { func testDeriveShieldedAddressFromSeed() throws {
let seedBytes = [UInt8](seedData) let seedBytes = [UInt8](seedData)
let shieldedAddress = try DerivationTool.default.deriveShieldedAddress(seed: seedBytes, accountIndex: 0) let shieldedAddress = try derivationTool.deriveShieldedAddress(seed: seedBytes, accountIndex: 0)
XCTAssertEqual(shieldedAddress, testRecipientAddress) XCTAssertEqual(shieldedAddress, testRecipientAddress)
} }
func testDeriveShieldedAddressFromViewingKey() throws { func testDeriveShieldedAddressFromViewingKey() throws {
XCTAssertEqual(try DerivationTool.default.deriveShieldedAddress(viewingKey: expectedViewingKey), testRecipientAddress) XCTAssertEqual(try derivationTool.deriveShieldedAddress(viewingKey: expectedViewingKey), testRecipientAddress)
} }
func testDeriveTransparentAddressFromSeed() throws { func testDeriveTransparentAddressFromSeed() throws {
XCTAssertEqual(try DerivationTool.default.deriveTransparentAddress(seed: [UInt8](seedData)), expectedTransparentAddress) XCTAssertEqual(try derivationTool.deriveTransparentAddress(seed: [UInt8](seedData)), expectedTransparentAddress)
} }
func testIsValidViewingKey() throws { func testIsValidViewingKey() throws {
XCTAssertTrue(try DerivationTool.default.isValidExtendedViewingKey("zxviews1q0dm7hkzqqqqpqplzv3f50rl4vay8uy5zg9e92f62lqg6gzu63rljety32xy5tcyenzuu3n386ws772nm6tp4sads8n37gff6nxmyz8dn9keehmapk0spc6pzx5uxepgu52xnwzxxnuja5tv465t9asppnj3eqncu3s7g3gzg5x8ss4ypkw08xwwyj7ky5skvnd9ldwj2u8fz2ry94s5q8p9lyp3j96yckudmp087d2jr2rnfuvjp7f56v78vpe658vljjddj7s645q399jd7")) XCTAssertTrue(try derivationTool.isValidExtendedViewingKey("zxviews1q0dm7hkzqqqqpqplzv3f50rl4vay8uy5zg9e92f62lqg6gzu63rljety32xy5tcyenzuu3n386ws772nm6tp4sads8n37gff6nxmyz8dn9keehmapk0spc6pzx5uxepgu52xnwzxxnuja5tv465t9asppnj3eqncu3s7g3gzg5x8ss4ypkw08xwwyj7ky5skvnd9ldwj2u8fz2ry94s5q8p9lyp3j96yckudmp087d2jr2rnfuvjp7f56v78vpe658vljjddj7s645q399jd7"))
XCTAssertFalse(try DerivationTool.default.isValidExtendedViewingKey("zxviews1q0dm7hkzky5skvnd9ldwj2u8fz2ry94s5q8p9lyp3j96yckudmp087d2jr2rnfuvjp7f56v78vpe658vljjddj7s645q399jd7")) XCTAssertFalse(try derivationTool.isValidExtendedViewingKey("zxviews1q0dm7hkzky5skvnd9ldwj2u8fz2ry94s5q8p9lyp3j96yckudmp087d2jr2rnfuvjp7f56v78vpe658vljjddj7s645q399jd7"))
} }
func testDeriveSecretKeyFromSeed() throws { func testDeriveSecretKeyFromSeed() throws {
XCTAssertEqual(try DerivationTool.default.deriveTransparentPrivateKey(seed: [UInt8](seedData)), "KwqfQoTCuQdCLvzpAEtkt1o8J62WJuZXD3cGRAf1bgmPWuLamHLo") XCTAssertEqual(try derivationTool.deriveTransparentPrivateKey(seed: [UInt8](seedData)), "KwqfQoTCuQdCLvzpAEtkt1o8J62WJuZXD3cGRAf1bgmPWuLamHLo")
} }
func testDeriveUnifiedKeysFromSeed() throws { func testDeriveUnifiedKeysFromSeed() throws {
let unifiedKeys = try DerivationTool.default.deriveUnifiedViewingKeysFromSeed([UInt8](seedData), numberOfAccounts: 1) let unifiedKeys = try derivationTool.deriveUnifiedViewingKeysFromSeed([UInt8](seedData), numberOfAccounts: 1)
XCTAssertEqual(unifiedKeys.count, 1) XCTAssertEqual(unifiedKeys.count, 1)
XCTAssertEqual(unifiedKeys[0].extfvk, expectedViewingKey) XCTAssertEqual(unifiedKeys[0].extfvk, expectedViewingKey)
XCTAssertEqual(expectedTransparentAddress, try DerivationTool.default.deriveTransparentAddressFromPublicKey(unifiedKeys[0].extpub)) XCTAssertEqual(expectedTransparentAddress, try derivationTool.deriveTransparentAddressFromPublicKey(unifiedKeys[0].extpub))
} }
func testDeriveQuiteALotOfUnifiedKeysFromSeed() throws { func testDeriveQuiteALotOfUnifiedKeysFromSeed() throws {
let unifiedKeys = try DerivationTool.default.deriveUnifiedViewingKeysFromSeed([UInt8](seedData), numberOfAccounts: 10) let unifiedKeys = try derivationTool.deriveUnifiedViewingKeysFromSeed([UInt8](seedData), numberOfAccounts: 10)
XCTAssertEqual(unifiedKeys.count, 10) XCTAssertEqual(unifiedKeys.count, 10)
XCTAssertEqual(unifiedKeys[0].extfvk, expectedViewingKey) XCTAssertEqual(unifiedKeys[0].extfvk, expectedViewingKey)
XCTAssertEqual(expectedTransparentAddress, try DerivationTool.default.deriveTransparentAddressFromPublicKey(unifiedKeys[0].extpub)) XCTAssertEqual(expectedTransparentAddress, try derivationTool.deriveTransparentAddressFromPublicKey(unifiedKeys[0].extpub))
} }
} }

View File

@ -26,6 +26,7 @@ end
target 'ZcashLightClientSample-Mainnet' do target 'ZcashLightClientSample-Mainnet' do
inherit! :search_paths inherit! :search_paths
use_frameworks! use_frameworks!
pod 'MnemonicSwift', '~> 2.0.0'
pod "KRProgressHUD" pod "KRProgressHUD"
pod 'PaginatedTableView' pod 'PaginatedTableView'
pod 'NotificationBubbles' pod 'NotificationBubbles'
@ -41,9 +42,7 @@ post_install do |installer|
if target.name == 'ZcashLightClientKit-Unit-Tests' if target.name == 'ZcashLightClientKit-Unit-Tests'
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = "13.0" config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = "13.0"
end end
if target.name == 'ZcashLightClientKit'
config.build_settings['ZCASH_NETWORK_ENVIRONMENT'] = ENV["ZCASH_NETWORK_ENVIRONMENT"]
end
config.build_settings['ENABLE_BITCODE'] = 'NO' config.build_settings['ENABLE_BITCODE'] = 'NO'
end end
end end

View File

@ -68,13 +68,13 @@ PODS:
- SwiftNIOFoundationCompat (< 3, >= 2.19.0) - SwiftNIOFoundationCompat (< 3, >= 2.19.0)
- SwiftNIOTLS (< 3, >= 2.19.0) - SwiftNIOTLS (< 3, >= 2.19.0)
- SwiftProtobuf (1.16.0) - SwiftProtobuf (1.16.0)
- ZcashLightClientKit (0.12.0-alpha.10): - ZcashLightClientKit (0.12.0-alpha.12):
- gRPC-Swift (= 1.0.0) - gRPC-Swift (= 1.0.0)
- SQLite.swift (~> 0.12.2) - SQLite.swift (~> 0.12.2)
- ZcashLightClientKit/DerivationToolTests (0.12.0-alpha.10): - ZcashLightClientKit/DerivationToolTests (0.12.0-alpha.12):
- gRPC-Swift (= 1.0.0) - gRPC-Swift (= 1.0.0)
- SQLite.swift (~> 0.12.2) - SQLite.swift (~> 0.12.2)
- ZcashLightClientKit/Tests (0.12.0-alpha.10): - ZcashLightClientKit/Tests (0.12.0-alpha.12):
- gRPC-Swift (= 1.0.0) - gRPC-Swift (= 1.0.0)
- SQLite.swift (~> 0.12.2) - SQLite.swift (~> 0.12.2)
@ -153,8 +153,8 @@ SPEC CHECKSUMS:
SwiftNIOTLS: 4f8df225f03393f08e0b47b4d876ae38167f8a27 SwiftNIOTLS: 4f8df225f03393f08e0b47b4d876ae38167f8a27
SwiftNIOTransportServices: 896c9a4ac98698d32aa2feea7657ade219ae80bb SwiftNIOTransportServices: 896c9a4ac98698d32aa2feea7657ade219ae80bb
SwiftProtobuf: 4e16842b83c6fda06b10fac50d73b3f1fce8ab7b SwiftProtobuf: 4e16842b83c6fda06b10fac50d73b3f1fce8ab7b
ZcashLightClientKit: cbd3df0c6736cbcb228b5cdc39baad40346ffba3 ZcashLightClientKit: 386288e87e90446638c2314a7b4f3f1ffeee40b5
PODFILE CHECKSUM: 315a67042788e1eccd948b2b8fe580222fd83cd9 PODFILE CHECKSUM: 0e90dc69ac4c19fd97c0ce4835ece810d79ade23
COCOAPODS: 1.10.1 COCOAPODS: 1.10.1

View File

@ -13,6 +13,9 @@
0D4EBA312396CFD70041B507 /* SendViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D4EBA302396CFD70041B507 /* SendViewController.swift */; }; 0D4EBA312396CFD70041B507 /* SendViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D4EBA302396CFD70041B507 /* SendViewController.swift */; };
0D6CE8BD252E3C4A0005D707 /* SaplingParametersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D6CE8BC252E3C4A0005D707 /* SaplingParametersViewController.swift */; }; 0D6CE8BD252E3C4A0005D707 /* SaplingParametersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D6CE8BC252E3C4A0005D707 /* SaplingParametersViewController.swift */; };
0D756A94236C761E009B041B /* GetAddressViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D756A93236C761E009B041B /* GetAddressViewController.swift */; }; 0D756A94236C761E009B041B /* GetAddressViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D756A93236C761E009B041B /* GetAddressViewController.swift */; };
0D76121726B1D5F5001CA417 /* Mainnet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D76121526B1D5ED001CA417 /* Mainnet.swift */; };
0D76121926B1D66D001CA417 /* Testnet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D76121826B1D66D001CA417 /* Testnet.swift */; };
0D76121A26B1E8F6001CA417 /* SampleLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D49A18B241698A800CC0649 /* SampleLogger.swift */; };
0D7A4A83236CCD88001F4DD8 /* SyncBlocksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D7A4A82236CCD88001F4DD8 /* SyncBlocksViewController.swift */; }; 0D7A4A83236CCD88001F4DD8 /* SyncBlocksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D7A4A82236CCD88001F4DD8 /* SyncBlocksViewController.swift */; };
0D7C85E523AD5A9B006878FC /* SampleStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D7C85E423AD5A9B006878FC /* SampleStorage.swift */; }; 0D7C85E523AD5A9B006878FC /* SampleStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D7C85E423AD5A9B006878FC /* SampleStorage.swift */; };
0D8BB45223B1DA0700D5E2A1 /* GetBalanceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD3DC6238D88B100DD3EC4 /* GetBalanceViewController.swift */; }; 0D8BB45223B1DA0700D5E2A1 /* GetBalanceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD3DC6238D88B100DD3EC4 /* GetBalanceViewController.swift */; };
@ -75,6 +78,8 @@
0D4EBA302396CFD70041B507 /* SendViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendViewController.swift; sourceTree = "<group>"; }; 0D4EBA302396CFD70041B507 /* SendViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendViewController.swift; sourceTree = "<group>"; };
0D6CE8BC252E3C4A0005D707 /* SaplingParametersViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaplingParametersViewController.swift; sourceTree = "<group>"; }; 0D6CE8BC252E3C4A0005D707 /* SaplingParametersViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaplingParametersViewController.swift; sourceTree = "<group>"; };
0D756A93236C761E009B041B /* GetAddressViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetAddressViewController.swift; sourceTree = "<group>"; }; 0D756A93236C761E009B041B /* GetAddressViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetAddressViewController.swift; sourceTree = "<group>"; };
0D76121526B1D5ED001CA417 /* Mainnet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mainnet.swift; sourceTree = "<group>"; };
0D76121826B1D66D001CA417 /* Testnet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Testnet.swift; sourceTree = "<group>"; };
0D7A4A82236CCD88001F4DD8 /* SyncBlocksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncBlocksViewController.swift; sourceTree = "<group>"; }; 0D7A4A82236CCD88001F4DD8 /* SyncBlocksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncBlocksViewController.swift; sourceTree = "<group>"; };
0D7C85E423AD5A9B006878FC /* SampleStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleStorage.swift; sourceTree = "<group>"; }; 0D7C85E423AD5A9B006878FC /* SampleStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleStorage.swift; sourceTree = "<group>"; };
0D8BB46C23B1DA0700D5E2A1 /* ZcashLightClientSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ZcashLightClientSample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0D8BB46C23B1DA0700D5E2A1 /* ZcashLightClientSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ZcashLightClientSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -189,6 +194,15 @@
path = "Get Address"; path = "Get Address";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
0D76121426B1D5D7001CA417 /* Constants */ = {
isa = PBXGroup;
children = (
0D76121526B1D5ED001CA417 /* Mainnet.swift */,
0D76121826B1D66D001CA417 /* Testnet.swift */,
);
path = Constants;
sourceTree = "<group>";
};
0D7A4A81236CCCDB001F4DD8 /* Sync Blocks */ = { 0D7A4A81236CCCDB001F4DD8 /* Sync Blocks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -224,6 +238,7 @@
0D907F142322CC5900D641FE /* ZcashLightClientSample */ = { 0D907F142322CC5900D641FE /* ZcashLightClientSample */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
0D76121426B1D5D7001CA417 /* Constants */,
0D1BE47D2581933C00F78BE3 /* Get UTXOs */, 0D1BE47D2581933C00F78BE3 /* Get UTXOs */,
0D1BE44F2581583D00F78BE3 /* Derivation Tool */, 0D1BE44F2581583D00F78BE3 /* Derivation Tool */,
0D6CE8BB252E3C1A0005D707 /* Sapling Parameters */, 0D6CE8BB252E3C1A0005D707 /* Sapling Parameters */,
@ -659,6 +674,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
0D76121726B1D5F5001CA417 /* Mainnet.swift in Sources */,
0D8BB45223B1DA0700D5E2A1 /* GetBalanceViewController.swift in Sources */, 0D8BB45223B1DA0700D5E2A1 /* GetBalanceViewController.swift in Sources */,
0D8BB45323B1DA0700D5E2A1 /* GetAddressViewController.swift in Sources */, 0D8BB45323B1DA0700D5E2A1 /* GetAddressViewController.swift in Sources */,
0D8BB45423B1DA0700D5E2A1 /* ViewController.swift in Sources */, 0D8BB45423B1DA0700D5E2A1 /* ViewController.swift in Sources */,
@ -672,6 +688,7 @@
0D8BB45C23B1DA0700D5E2A1 /* SampleStorage.swift in Sources */, 0D8BB45C23B1DA0700D5E2A1 /* SampleStorage.swift in Sources */,
0D8BB45D23B1DA0700D5E2A1 /* TransactionsDataSource.swift in Sources */, 0D8BB45D23B1DA0700D5E2A1 /* TransactionsDataSource.swift in Sources */,
0D8BB45E23B1DA0700D5E2A1 /* PaginatedTransactionsViewController.swift in Sources */, 0D8BB45E23B1DA0700D5E2A1 /* PaginatedTransactionsViewController.swift in Sources */,
0D76121A26B1E8F6001CA417 /* SampleLogger.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -684,6 +701,7 @@
0D907F182322CC5900D641FE /* ViewController.swift in Sources */, 0D907F182322CC5900D641FE /* ViewController.swift in Sources */,
0DDFB33C236B743000AED892 /* LatestHeightViewController.swift in Sources */, 0DDFB33C236B743000AED892 /* LatestHeightViewController.swift in Sources */,
0DBF8F9523A80F5A0010B85F /* TransactionDetailViewController.swift in Sources */, 0DBF8F9523A80F5A0010B85F /* TransactionDetailViewController.swift in Sources */,
0D76121926B1D66D001CA417 /* Testnet.swift in Sources */,
0DA58B942397DDD9004596EA /* TransactionsTableViewController.swift in Sources */, 0DA58B942397DDD9004596EA /* TransactionsTableViewController.swift in Sources */,
0D4EBA312396CFD70041B507 /* SendViewController.swift in Sources */, 0D4EBA312396CFD70041B507 /* SendViewController.swift in Sources */,
0D7A4A83236CCD88001F4DD8 /* SyncBlocksViewController.swift in Sources */, 0D7A4A83236CCD88001F4DD8 /* SyncBlocksViewController.swift in Sources */,

View File

@ -33,11 +33,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
if let wallet = wallet { if let wallet = wallet {
return wallet return wallet
} else { } else {
let unifiedViewingKeys = try! DerivationTool.default.deriveUnifiedViewingKeysFromSeed(DemoAppConfig.seed, numberOfAccounts: 1) let unifiedViewingKeys = try! DerivationTool(networkType: ZCASH_NETWORK.networkType).deriveUnifiedViewingKeysFromSeed(DemoAppConfig.seed, numberOfAccounts: 1)
let wallet = Initializer(cacheDbURL:try! __cacheDbURL(), let wallet = Initializer(cacheDbURL:try! __cacheDbURL(),
dataDbURL: try! __dataDbURL(), dataDbURL: try! __dataDbURL(),
pendingDbURL: try! __pendingDbURL(), pendingDbURL: try! __pendingDbURL(),
endpoint: DemoAppConfig.endpoint, endpoint: DemoAppConfig.endpoint,
network: ZCASH_NETWORK,
spendParamsURL: try! __spendParamsURL(), spendParamsURL: try! __spendParamsURL(),
outputParamsURL: try! __outputParamsURL(), outputParamsURL: try! __outputParamsURL(),
viewingKeys: unifiedViewingKeys, viewingKeys: unifiedViewingKeys,
@ -48,7 +49,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
try! wallet.initialize() try! wallet.initialize()
var storage = SampleStorage.shared var storage = SampleStorage.shared
storage!.seed = Data(DemoAppConfig.seed) storage!.seed = Data(DemoAppConfig.seed)
storage!.privateKey = try! DerivationTool.default.deriveSpendingKeys(seed: DemoAppConfig.seed, numberOfAccounts: 1)[0] storage!.privateKey = try! DerivationTool(networkType: ZCASH_NETWORK.networkType).deriveSpendingKeys(seed: DemoAppConfig.seed, numberOfAccounts: 1)[0]
self.wallet = wallet self.wallet = wallet
return wallet return wallet
} }
@ -152,15 +153,15 @@ func __documentsDirectory() throws -> URL {
} }
func __cacheDbURL() throws -> URL { func __cacheDbURL() throws -> URL {
try __documentsDirectory().appendingPathComponent(ZcashSDK.DEFAULT_DB_NAME_PREFIX+ZcashSDK.DEFAULT_CACHES_DB_NAME, isDirectory: false) try __documentsDirectory().appendingPathComponent(ZCASH_NETWORK.constants.DEFAULT_DB_NAME_PREFIX+ZcashSDK.DEFAULT_CACHES_DB_NAME, isDirectory: false)
} }
func __dataDbURL() throws -> URL { func __dataDbURL() throws -> URL {
try __documentsDirectory().appendingPathComponent(ZcashSDK.DEFAULT_DB_NAME_PREFIX+ZcashSDK.DEFAULT_DATA_DB_NAME, isDirectory: false) try __documentsDirectory().appendingPathComponent(ZCASH_NETWORK.constants.DEFAULT_DB_NAME_PREFIX+ZcashSDK.DEFAULT_DATA_DB_NAME, isDirectory: false)
} }
func __pendingDbURL() throws -> URL { func __pendingDbURL() throws -> URL {
try __documentsDirectory().appendingPathComponent(ZcashSDK.DEFAULT_DB_NAME_PREFIX+ZcashSDK.DEFAULT_PENDING_DB_NAME) try __documentsDirectory().appendingPathComponent(ZCASH_NETWORK.constants.DEFAULT_DB_NAME_PREFIX+ZcashSDK.DEFAULT_PENDING_DB_NAME)
} }
func __spendParamsURL() throws -> URL { func __spendParamsURL() throws -> URL {

View File

@ -0,0 +1,12 @@
//
// Mainnet.swift
// ZcashLightClientSample
//
// Created by Francisco Gindre on 7/28/21.
// Copyright © 2021 Electric Coin Company. All rights reserved.
//
import Foundation
import ZcashLightClientKit
let ZCASH_NETWORK = ZcashNetworkBuilder.network(for: .mainnet)

View File

@ -0,0 +1,12 @@
//
// Testnet.swift
// ZcashLightClientSample
//
// Created by Francisco Gindre on 7/28/21.
// Copyright © 2021 Electric Coin Company. All rights reserved.
//
import Foundation
import ZcashLightClientKit
let ZCASH_NETWORK = ZcashNetworkBuilder.network(for: .testnet)

View File

@ -13,17 +13,15 @@ struct DemoAppConfig {
static var host = ZcashSDK.isMainnet ? "lightwalletd.electriccoin.co" : "lightwalletd.testnet.electriccoin.co" static var host = ZcashSDK.isMainnet ? "lightwalletd.electriccoin.co" : "lightwalletd.testnet.electriccoin.co"
static var port: Int = 9067 static var port: Int = 9067
static var birthdayHeight: BlockHeight = ZcashSDK.isMainnet ? 935000 : 1386000 static var birthdayHeight: BlockHeight = ZcashSDK.isMainnet ? 935000 : 1386000
static var network = ZcashSDK.isMainnet ? ZcashNetwork.mainNet : ZcashNetwork.testNet
static var seed = try! Mnemonic.deterministicSeedBytes(from: "live combine flight accident slow soda mind bright absent bid hen shy decade biology amazing mix enlist ensure biology rhythm snap duty soap armor") static var seed = try! Mnemonic.deterministicSeedBytes(from: "live combine flight accident slow soda mind bright absent bid hen shy decade biology amazing mix enlist ensure biology rhythm snap duty soap armor")
static var address: String { static var address: String {
"\(host):\(port)" "\(host):\(port)"
} }
static var processorConfig: CompactBlockProcessor.Configuration { static var processorConfig: CompactBlockProcessor.Configuration = {
var config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL()) CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), walletBirthday: Self.birthdayHeight, network: ZCASH_NETWORK)
config.walletBirthday = self.birthdayHeight }()
return config
}
static var endpoint: LightWalletEndpoint { static var endpoint: LightWalletEndpoint {
return LightWalletEndpoint(address: self.host, port: self.port, secure: true) return LightWalletEndpoint(address: self.host, port: self.port, secure: true)
@ -31,7 +29,13 @@ struct DemoAppConfig {
} }
enum ZcashNetwork { extension ZcashSDK {
case mainNet static var isMainnet: Bool {
case testNet switch ZCASH_NETWORK.networkType {
case .mainnet:
return true
case .testnet:
return false
}
}
} }

View File

@ -81,19 +81,19 @@ class DerivationToolViewController: UIViewController {
} }
func deriveFrom(seedPhrase: String) throws { func deriveFrom(seedPhrase: String) throws {
let seedBytes = try Mnemonic.deterministicSeedBytes(from: seedPhrase) let seedBytes = try Mnemonic.deterministicSeedBytes(from: seedPhrase)
guard let spendingKey = try DerivationTool.default.deriveSpendingKeys(seed: seedBytes, numberOfAccounts: 1).first else { let derivationTool = DerivationTool(networkType: ZCASH_NETWORK.networkType)
guard let spendingKey = try derivationTool.deriveSpendingKeys(seed: seedBytes, numberOfAccounts: 1).first else {
throw DerivationErrors.couldNotDeriveSpendingKeys(underlyingError: DerivationErrors.unknown) throw DerivationErrors.couldNotDeriveSpendingKeys(underlyingError: DerivationErrors.unknown)
} }
guard let viewingKey = try DerivationTool.default.deriveViewingKeys(seed: seedBytes, numberOfAccounts: 1).first else { guard let viewingKey = try derivationTool.deriveViewingKeys(seed: seedBytes, numberOfAccounts: 1).first else {
throw DerivationErrors.couldNotDeriveViewingKeys(underlyingError: DerivationErrors.unknown) throw DerivationErrors.couldNotDeriveViewingKeys(underlyingError: DerivationErrors.unknown)
} }
let shieldedAddress = try DerivationTool.default.deriveShieldedAddress(viewingKey: viewingKey) let shieldedAddress = try derivationTool.deriveShieldedAddress(viewingKey: viewingKey)
let transparentAddress = try DerivationTool.default.deriveTransparentAddress(seed: seedBytes) let transparentAddress = try derivationTool.deriveTransparentAddress(seed: seedBytes)
updateLabels(spendingKey: spendingKey, updateLabels(spendingKey: spendingKey,

View File

@ -15,11 +15,11 @@ class GetAddressViewController: UIViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
let derivationTool = DerivationTool(networkType: ZCASH_NETWORK.networkType)
// Do any additional setup after loading the view. // Do any additional setup after loading the view.
zAddressLabel.text = (try? DerivationTool.default.deriveShieldedAddress(seed: DemoAppConfig.seed, accountIndex: 0)) ?? "No Addresses found" zAddressLabel.text = (try? derivationTool.deriveShieldedAddress(seed: DemoAppConfig.seed, accountIndex: 0)) ?? "No Addresses found"
tAddressLabel.text = (try? DerivationTool.default.deriveTransparentAddress(seed: DemoAppConfig.seed)) ?? "could not derive t-address" tAddressLabel.text = (try? derivationTool.deriveTransparentAddress(seed: DemoAppConfig.seed)) ?? "could not derive t-address"
spendingKeyLabel.text = SampleStorage.shared.privateKey ?? "No Spending Key found" spendingKeyLabel.text = SampleStorage.shared.privateKey ?? "No Spending Key found"
zAddressLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(addressTapped(_:)))) zAddressLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(addressTapped(_:))))
zAddressLabel.isUserInteractionEnabled = true zAddressLabel.isUserInteractionEnabled = true
@ -60,7 +60,7 @@ class GetAddressViewController: UIViewController {
@IBAction func addressTapped(_ gesture: UIGestureRecognizer) { @IBAction func addressTapped(_ gesture: UIGestureRecognizer) {
loggerProxy.event("copied to clipboard") loggerProxy.event("copied to clipboard")
UIPasteboard.general.string = try? DerivationTool.default.deriveShieldedAddress(seed: DemoAppConfig.seed, accountIndex: 0) UIPasteboard.general.string = try? DerivationTool(networkType: ZCASH_NETWORK.networkType).deriveShieldedAddress(seed: DemoAppConfig.seed, accountIndex: 0)
let alert = UIAlertController(title: "", message: "Address Copied to clipboard", preferredStyle: UIAlertController.Style.alert) let alert = UIAlertController(title: "", message: "Address Copied to clipboard", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil)) alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil) self.present(alert, animated: true, completion: nil)
@ -68,7 +68,7 @@ class GetAddressViewController: UIViewController {
@IBAction func tAddressTapped(_ gesture: UIGestureRecognizer) { @IBAction func tAddressTapped(_ gesture: UIGestureRecognizer) {
loggerProxy.event("copied to clipboard") loggerProxy.event("copied to clipboard")
UIPasteboard.general.string = try? DerivationTool.default.deriveTransparentAddress(seed: DemoAppConfig.seed) UIPasteboard.general.string = try? DerivationTool(networkType: ZCASH_NETWORK.networkType).deriveTransparentAddress(seed: DemoAppConfig.seed)
let alert = UIAlertController(title: "", message: "Address Copied to clipboard", preferredStyle: UIAlertController.Style.alert) let alert = UIAlertController(title: "", message: "Address Copied to clipboard", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil)) alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil) self.present(alert, animated: true, completion: nil)

View File

@ -26,10 +26,10 @@ class GetUTXOsViewController: UIViewController {
} }
func updateUI() { func updateUI() {
let tAddress = try! DerivationTool.default.deriveTransparentAddress(seed: DemoAppConfig.seed) let tAddress = try! DerivationTool(networkType: ZCASH_NETWORK.networkType).deriveTransparentAddress(seed: DemoAppConfig.seed)
self.transparentAddressLabel.text = tAddress self.transparentAddressLabel.text = tAddress
let balance = try! AppDelegate.shared.sharedSynchronizer.getTransparentBalance(address: tAddress) let balance = try! AppDelegate.shared.sharedSynchronizer.getTransparentBalance(accountIndex: 0)
self.totalBalanceLabel.text = String(balance.total.asHumanReadableZecBalance()) self.totalBalanceLabel.text = String(balance.total.asHumanReadableZecBalance())
self.verifiedBalanceLabel.text = String(balance.verified.asHumanReadableZecBalance()) self.verifiedBalanceLabel.text = String(balance.verified.asHumanReadableZecBalance())
@ -38,9 +38,10 @@ class GetUTXOsViewController: UIViewController {
@IBAction func shieldFunds(_ sender: Any) { @IBAction func shieldFunds(_ sender: Any) {
do { do {
let seed = DemoAppConfig.seed let seed = DemoAppConfig.seed
let sk = try DerivationTool.default.deriveSpendingKeys(seed: seed, numberOfAccounts: 1).first! let derivationTool = DerivationTool(networkType: ZCASH_NETWORK.networkType)
let sk = try derivationTool.deriveSpendingKeys(seed: seed, numberOfAccounts: 1).first!
let tsk = try DerivationTool.default.deriveTransparentPrivateKey(seed: seed) let tsk = try derivationTool.deriveTransparentPrivateKey(seed: seed)
KRProgressHUD.showMessage("🛡 Shielding 🛡") KRProgressHUD.showMessage("🛡 Shielding 🛡")
AppDelegate.shared.sharedSynchronizer.shieldFunds(spendingKey: sk, transparentSecretKey: tsk, memo: "shielding is fun!", from: 0) { (result) in AppDelegate.shared.sharedSynchronizer.shieldFunds(spendingKey: sk, transparentSecretKey: tsk, memo: "shielding is fun!", from: 0) { (result) in
DispatchQueue.main.async { DispatchQueue.main.async {

View File

@ -43,16 +43,13 @@ use_frameworks!
pod 'ZcashLightClientKit' pod 'ZcashLightClientKit'
```` ````
### Set Testnet or Mainnet environment
Before building, make sure that your environment has the variable `ZCASH_NETWORK_ENVIRONMENT` set to `MAINNET` or `TESTNET`.
### Custom build phases warning ### Custom build phases warning
When running `pod install` you will see this warning upon success: When running `pod install` you will see this warning upon success:
```` bash ```` bash
[!] ZcashLightClientKit has added 2 script phases. Please inspect before executing a build. [!] ZcashLightClientKit has added 2 script phases. Please inspect before executing a build.
See `https://guides.cocoapods.org/syntax/podspec.html#script_phases` for more information. See `https://guides.cocoapods.org/syntax/podspec.html#script_phases` for more information.
```` ````
Integrating Rust code with Swift code and delivering it in a consistent and (build) reproducible way, is hard. We've taken the lead to get that burden off your shoulders as much as possible by leveraging the `prepare_command` and `script_phases` features from Cocoapods to carefully generate the `TESTNET` and `MAINNET` builds as simple and less error prone as we could think it could be. Which started as some simple vanilla scripts, ended up being some kind of "Build System" on its own. Nothing is written on stone, and we accept collaborations and improvements in this matter too. Integrating Rust code with Swift code and delivering it in a consistent and (build) reproducible way, is hard. We've taken the lead to get that burden off your shoulders as much as possible by leveraging the `prepare_command` and `script_phases` features from Cocoapods to carefully generate a build for the Rust layer.
## Build system ## Build system
@ -68,8 +65,7 @@ ZcashLightClientKit needs files to be present at pod installation time, but that
- `${ZCASH_POD_SRCROOT}/zcashlc/libzcashlc.a` this is the librustzcash build .a file itself - `${ZCASH_POD_SRCROOT}/zcashlc/libzcashlc.a` this is the librustzcash build .a file itself
- `lib/libzcashlc.a` (as vendored library that will be added as an asset by xcodeproj) - `lib/libzcashlc.a` (as vendored library that will be added as an asset by xcodeproj)
- `ZcashSDK.generated.swift` which contains sensitive values for the SDK that change depending on the network environment we are building for
- `WalletBirthday+saplingtree.generated.swift` helper functions to import existing wallets
**2. Build Phase** **2. Build Phase**
@ -78,37 +74,17 @@ The build Phase scripts executes within the Xcode Build Step and has all the kno
```` ruby ```` ruby
s.script_phase = { s.script_phase = {
:name => 'Build generate constants and build librustzcash', :name => 'Build generate constants and build librustzcash',
:script => 'sh ${PODS_TARGET_SRCROOT}/Scripts/generate_zcashsdk_constants.sh && sh ${PODS_TARGET_SRCROOT}/Scripts/build_librustzcash_xcode.sh', :script => 'sh ${PODS_TARGET_SRCROOT}/Scripts/build_librustzcash_xcode.sh',
:execution_position => :before_compile :execution_position => :before_compile
} }
```` ````
This step will generate files needed on the next steps and build the librustzcash with Xcode but *not using cargo's built-in Xcode integration* This step will generate files needed on the next steps and build the librustzcash with Xcode but *not using cargo's built-in Xcode integration*
**a. Generating ZcashSDK constants** ** Building librustzcash and integrating it to the pod structure**
To run this you need `Sourcery`. We use `Stencil` templates to create these files based on the `ZCASH_NETWORK_ENVIRONMENT` value of your choice. You can either integrate sourcery with cocoapods or as part of your environment.
All generated files will be located in the Pods source root within the `Generated` folder. `ZCASH_SDK_GENERATED_SOURCES_FOLDER` represents that path in the build system.
**b. Building librustzcash and integrating it to the pod structure**
Where the magic happens. Here we will make sure that everything is set up properly to start building librustzcash. When on mainnet, the build will append a parameter to include mainnet features. Where the magic happens. Here we will make sure that everything is set up properly to start building librustzcash. When on mainnet, the build will append a parameter to include mainnet features.
**Safeguards points**:
if it appears that you are about to build something smelly, we will let you know. Combining testnet and mainnet values and artifacts and viceversa leads to unstable builds and may cause loss of funds if ran on production.
```
if [ existing_build_mismatch = true ]; then
# clean
echo "build mismatch. You previously build a Different network environment. It appears that your build could be inconsistent if proceeding. Please clean your Pods/ folder and clean your build before running your next build."
exit 1
fi
```
**3. Xcode clean integration**
When performing a clean, we will clean the rust build folders.
### Scripts ### Scripts
On the Scripts folder you will find the following files: On the Scripts folder you will find the following files:
@ -118,12 +94,11 @@ On the Scripts folder you will find the following files:
|-/generate_test_constants.sh |-/generate_test_constants.sh
|-/build_librustzcash_xcode.sh |-/build_librustzcash_xcode.sh
|-/build_librustzcash.sh |-/build_librustzcash.sh
|-/generate_zcashsdk_constants.sh
|-/script_commons.sh |-/script_commons.sh
```` ````
#### prepare_zcash_sdk.sh #### prepare_zcash_sdk.sh
This script is run by the Cocoapods 'preapare_command'. This script is run by the Cocoapods 'prepare_command'.
```` Ruby ```` Ruby
s.prepare_command = <<-CMD s.prepare_command = <<-CMD
@ -194,22 +169,7 @@ We don't like reinventing the wheel, so we gently borrowed swift lint rules from
## Troubleshooting ## Troubleshooting
### No network environment.... #### clean pod install
if you see this message when building:
```No network environment. Set ZCASH_NETWORK_ENVIRONMENT to MAINNET or TESTNET```
make sure your dev environment has this variable set before the build starts. *DO NOT CHANGE IT DURING THE BUILD PROCESS*.
If the variable was properly set *after* you've seen this message, you will need to either a) set it manually on the pod's target or b) doing a clean pod install and subsequent build.
#### a) setting the flag manually
1. on your workspace, select the Pods project
2. on the Targets pane, select ZcashLightClientKit
3. go to build settings
4. scroll down to see ZCASH_NETWORK_ENVIRONMENT and complete with TESTNET or MAINNET
![how to complete network environment manually](docs/images/complete_environment_manually.png)
#### b) clean pod install
it's not necessary to delete the whole Pods/ directory and download all of your dependencies again it's not necessary to delete the whole Pods/ directory and download all of your dependencies again
1. on your project root, locate the `Pods/` directory 1. on your project root, locate the `Pods/` directory
2. remove ZcashLightClientKit from it 2. remove ZcashLightClientKit from it
@ -228,14 +188,6 @@ if you get a build error similar to ```_function_name referenced from...```
3. run `pod install` 3. run `pod install`
4. build 4. build
### ZcashLightClientKitSample missing .params
ZcashLightClientKit has an external dependency on 2 files containing Sapling parameters. Although you can provide those files as you seem fit, the sample app requires them on the main bundle.
You can download these files from https://z.cash/downloads/sapling-spend.params
and https://z.cash/downloads/sapling-output.params and then move them to the correct folder, which is specified on the error itself.
![how to fix missing params files](docs/images/output_params_error.png)
### can't find crate for ... target may not be installed ### can't find crate for ... target may not be installed
This error could be a side effect of having more then one rust toolchain installed. This error could be a side effect of having more then one rust toolchain installed.
If you worked with ZcashLightClientKit 0.6.6 or below you might have had to set the compiler to 1.40.0 which can cause this compilation error to happen. If you worked with ZcashLightClientKit 0.6.6 or below you might have had to set the compiler to 1.40.0 which can cause this compilation error to happen.

View File

@ -3,16 +3,6 @@
BASEPATH="${PWD}" BASEPATH="${PWD}"
TARGET_DIR="target" TARGET_DIR="target"
FEATURE_FLAGS="--features=mainnet"
NETWORK_TYPE="TESTNET"
FLAVOR_FOLDER="Testnet"
if [ $1 = "--mainnet" ]; then
FEATURE_FLAGS="--features=mainnet"
NETWORK_TYPE="MAINNET"
FLAVOR_FOLDER="Mainnet"
fi
LIB_PATH="ZcashLightClientKit/$FLAVOR_FOLDER/zcashlc" LIB_PATH="ZcashLightClientKit/$FLAVOR_FOLDER/zcashlc"
echo "++++ Building librustzcash $NETWORK_TYPE library ++++" echo "++++ Building librustzcash $NETWORK_TYPE library ++++"
@ -22,7 +12,7 @@ if [ -f $TARGET_DIR ]; then
rm -rf $TARGET_DIR rm -rf $TARGET_DIR
fi fi
cargo build --release $FEATURE_FLAGS && cargo lipo --release cargo lipo --manifest-path ${PODS_TARGET_SRCROOT}/Cargo.toml --release
if [ -f $LIB_PATH ]; then if [ -f $LIB_PATH ]; then

View File

@ -7,31 +7,12 @@ if [ ! -f $SCRIPT_COMMONS ]; then
fi fi
source $SCRIPT_COMMONS source $SCRIPT_COMMONS
if [ "$1" = "--testing" ]; then
export ZCASH_NETWORK_ENVIRONMENT=$ZCASH_TESTNET
echo "Testing flag detected, forcing $ZCASH_TESTNET"
fi
check_environment
if [ "$ACTION" = "clean" ]; then if [ "$ACTION" = "clean" ]; then
echo "CLEAN DETECTED" echo "CLEAN DETECTED"
clean clean
exit 0 exit 0
fi fi
if [ existing_build_mismatch = true ]; then
# clean
echo "Build mismatch. You previously built a different network environment. It appears that your build could be inconsistent if proceeding. Please clean your Pods/ folder and clean your build before running your next build."
exit 1
fi
if is_mainnet; then
FEATURE_FLAGS="--features=mainnet"
else
FEATURE_FLAGS="--features=testnet"
fi
echo "Building Rust backend" echo "Building Rust backend"
echo "" echo ""
echo "platform name" echo "platform name"
@ -45,7 +26,7 @@ fi
echo "fix 'permission denied issue'" echo "fix 'permission denied issue'"
chmod -R +w ${PODS_TARGET_SRCROOT} chmod -R +w ${PODS_TARGET_SRCROOT}
echo "cargo lipo --manifest-path ${PODS_TARGET_SRCROOT}/Cargo.toml $FEATURE_FLAGS --targets $ZCASH_ACTIVE_ARCHITECTURE --release" echo "cargo lipo --manifest-path ${PODS_TARGET_SRCROOT}/Cargo.toml --targets $ZCASH_ACTIVE_ARCHITECTURE --release"
if [[ -n "${DEVELOPER_SDK_DIR:-}" ]]; then if [[ -n "${DEVELOPER_SDK_DIR:-}" ]]; then
# Assume we're in Xcode, which means we're probably cross-compiling. # Assume we're in Xcode, which means we're probably cross-compiling.
# In this case, we need to add an extra library search path for build scripts and proc-macros, # In this case, we need to add an extra library search path for build scripts and proc-macros,
@ -55,7 +36,7 @@ if [[ -n "${DEVELOPER_SDK_DIR:-}" ]]; then
export LIBRARY_PATH="${DEVELOPER_SDK_DIR}/MacOSX.sdk/usr/lib:${LIBRARY_PATH:-}" export LIBRARY_PATH="${DEVELOPER_SDK_DIR}/MacOSX.sdk/usr/lib:${LIBRARY_PATH:-}"
fi fi
if [ ! -f ${ZCASH_LIB_RUST_BUILD_PATH}/universal/release/${ZCASH_LIB_RUST_NAME} ]; then if [ ! -f ${ZCASH_LIB_RUST_BUILD_PATH}/universal/release/${ZCASH_LIB_RUST_NAME} ]; then
cargo lipo --manifest-path ${PODS_TARGET_SRCROOT}/Cargo.toml $FEATURE_FLAGS --targets $ZCASH_ACTIVE_ARCHITECTURE --release cargo lipo --manifest-path ${PODS_TARGET_SRCROOT}/Cargo.toml --targets $ZCASH_ACTIVE_ARCHITECTURE --release
persist_environment persist_environment
fi fi

View File

@ -1,42 +0,0 @@
#!/bin/sh
SCRIPT_COMMONS="${PODS_TARGET_SRCROOT}/Scripts/script_commons.sh"
if [ -f $SCRIPT_COMMONS ]; then
source $SCRIPT_COMMONS
else
echo "Failed to load $SCRIPT_COMMONS"
exit 1
fi
if ! hash sourcery; then
echo "Sourcery not found on your PATH"
exit 1
fi
export ZCASH_SDK_TEMPLATE="${ZCASH_SRC_PATH}/Stencil"
echo "export ZCASH_SRC_PATH=${ZCASH_SRC_PATH}"
check_environment
if is_mainnet; then
SOURCERY_ARGS="--args dbprefix=ZcashSdk_mainnet_ --args ismainnet=true --args saplingActivationHeight=419_200"
else
SOURCERY_ARGS="--args dbprefix=ZcashSdk_testnet_ --args ismainnet=false --args saplingActivationHeight=280_000"
fi
if [ -d $ZCASH_SDK_GENERATED_SOURCES_FOLDER ]; then
echo "clean up before generating new files: $ZCASH_SDK_GENERATED_SOURCES_FOLDER"
echo "rm -rf ${ZCASH_SDK_GENERATED_SOURCES_FOLDER}/*.generated*"
rm -rf "${ZCASH_SDK_GENERATED_SOURCES_FOLDER}/*.generated*"
else
echo "mkdir -p -v $ZCASH_SDK_GENERATED_SOURCES_FOLDER"
mkdir -p -v ${ZCASH_SDK_GENERATED_SOURCES_FOLDER}
fi
echo "Set +w to ${ZCASH_SDK_GENERATED_SOURCES_FOLDER}"
chmod -R +w ${ZCASH_SDK_GENERATED_SOURCES_FOLDER}
echo "sourcery --prune --verbose --templates ${ZCASH_SDK_TEMPLATE} --sources ${ZCASH_SRC_PATH} --output ${ZCASH_SDK_GENERATED_SOURCES_FOLDER} $SOURCERY_ARGS "
sourcery --prune --verbose --templates ${ZCASH_SDK_TEMPLATE} --sources ${ZCASH_SRC_PATH} --output ${ZCASH_SDK_GENERATED_SOURCES_FOLDER} $SOURCERY_ARGS

View File

@ -26,22 +26,3 @@ echo "**************************************************************************
echo " touch ${ZCASH_POD_ROOT}/zcashlc/zcashlc.h" echo " touch ${ZCASH_POD_ROOT}/zcashlc/zcashlc.h"
echo "***************************************************************************" echo "***************************************************************************"
touch ${ZCASH_POD_SRCROOT}/zcashlc/zcashlc.h touch ${ZCASH_POD_SRCROOT}/zcashlc/zcashlc.h
echo "make ${ZCASH_SDK_GENERATED_SOURCES_FOLDER} folder"
mkdir -p ${ZCASH_SDK_GENERATED_SOURCES_FOLDER}
echo "**********************************************"
echo "* create empty ZcashSDK.generated.swift file *"
echo "**********************************************"
echo ""
echo "touch ${ZCASH_SDK_GENERATED_SOURCES_FOLDER}/ZcashSDK.generated.swift"
touch ${ZCASH_SDK_GENERATED_SOURCES_FOLDER}/ZcashSDK.generated.swift
echo "****************************************************************"
echo "* create empty WalletBirthday+saplingtree.generated.swift file *"
echo "****************************************************************"
echo ""
echo "touch $ZCASH_SDK_GENERATED_SOURCES_FOLDER/WalletBirthday+saplingtree.generated.swift"
touch $ZCASH_SDK_GENERATED_SOURCES_FOLDER/WalletBirthday+saplingtree.generated.swift

View File

@ -4,14 +4,12 @@ export PATH="$HOME/.cargo/bin:$PATH"
export RUST_LIB_PATH="${PODS_TARGET_SRCROOT}/lib" export RUST_LIB_PATH="${PODS_TARGET_SRCROOT}/lib"
export ZCASH_POD_SCRIPTS="${PODS_TARGET_SRCROOT}/Scripts" export ZCASH_POD_SCRIPTS="${PODS_TARGET_SRCROOT}/Scripts"
export ZCASH_LIB_RUST_BUILD_PATH="${PODS_TARGET_SRCROOT}/target" export ZCASH_LIB_RUST_BUILD_PATH="${PODS_TARGET_SRCROOT}/target"
export ZCASH_BUILD_TYPE_MAINNET_FLAG=".mainnet_build"
export ZCASH_BUILD_TYPE_TESTNET_FLAG=".testnet_build"
export ZCASH_LIB_RUST_NAME="libzcashlc.a" export ZCASH_LIB_RUST_NAME="libzcashlc.a"
export ZCASH_TESTNET="TESTNET"
export ZCASH_MAINNET="MAINNET"
export ZCASH_SRC_PATH="${PODS_TARGET_SRCROOT}/ZcashLightClientKit" export ZCASH_SRC_PATH="${PODS_TARGET_SRCROOT}/ZcashLightClientKit"
export ZCASH_SDK_RUST_LIB_PATH="${ZCASH_SRC_PATH}/zcashlc" export ZCASH_SDK_RUST_LIB_PATH="${ZCASH_SRC_PATH}/zcashlc"
export ZCASH_SDK_GENERATED_SOURCES_FOLDER="${ZCASH_SRC_PATH}/Generated"
function clean { function clean {
echo "CLEAN DETECTED" echo "CLEAN DETECTED"
@ -23,76 +21,3 @@ function clean {
rm -rf "${ZCASH_LIB_RUST_BUILD_PATH}" rm -rf "${ZCASH_LIB_RUST_BUILD_PATH}"
fi fi
} }
function check_environment {
if [[ $ZCASH_NETWORK_ENVIRONMENT != $ZCASH_MAINNET ]] && [[ $ZCASH_NETWORK_ENVIRONMENT != $ZCASH_TESTNET ]]; then
echo "No network environment. Set ZCASH_NETWORK_ENVIRONMENT to $ZCASH_MAINNET or $ZCASH_TESTNET"
exit 1
fi
if [[ ! $ZCASH_SDK_GENERATED_SOURCES_FOLDER ]]; then
echo "No 'ZCASH_SDK_GENERATED_SOURCES_FOLDER' variable present. Delete Pods/ and run 'pod install --verbose'"
exit 1
fi
echo "**** Building for $ZCASH_NETWORK_ENVIRONMENT environment ****"
}
function is_mainnet {
if [[ $ZCASH_NETWORK_ENVIRONMENT = $ZCASH_MAINNET ]]; then
true
else
false
fi
}
# Return success (0) if there is a build mismatch, else failure (1) if no mismatch.
function existing_build_mismatch {
#if build exists check that corresponds to the current network environment
if [! -d $ZCASH_LIB_RUST_BUILD_PATH ]; then
return 1
fi
# there's a MAINNET Flag and MAINNET ENVIRONMENT
if [ -f "$ZCASH_LIB_RUST_BUILD_PATH/$ZCASH_BUILD_TYPE_MAINNET_FLAG" ] && [[ "$ZCASH_NETWORK_ENVIRONMENT" = "$ZCASH_MAINNET" ]]
then
return 1 # no build mismatch
fi
if [ -f "$ZCASH_LIB_RUST_BUILD_PATH/$ZCASH_BUILD_TYPE_MAINNET_FLAG" ] && [[ "$ZCASH_NETWORK_ENVIRONMENT" = "$ZCASH_TESTNET" ]]
then
warn_mismatch $ZCASH_MAINNET $ZCASH_NETWORK_ENVIRONMENT
return 0 # build mismatch in place
fi
# There's a TESTNET flag and we are on TESTNET ENVIRONMENT
if [ -f "$ZCASH_LIB_RUST_BUILD_PATH/$ZCASH_BUILD_TYPE_TESTNET_FLAG" ] && [[ "$ZCASH_NETWORK_ENVIRONMENT" = "$ZCASH_TESTNET" ]]
then
return 1 # no build mismatch
fi
# There's a TESTNET flag and we are on a MAINNET Environment
if [ -f "$ZCASH_LIB_RUST_BUILD_PATH/$ZCASH_BUILD_TYPE_TESTNET_FLAG" ] && [[ "$ZCASH_NETWORK_ENVIRONMENT" = "$ZCASH_MAINNET" ]]
then
warn_mismatch $ZCASH_TESTNET $ZCASH_NETWORK_ENVIRONMENT
return 0 # build mismatch in place
fi
echo "=== NO BUILD FLAG, CHECKING ENVIRONMENT ==="
check_environment
return 1 # no build mismatch
}
function warn_mismatch {
echo "*** WARNING: *** build mismatch. Found ${0} but environment is ${1}"
}
function persist_environment {
check_environment
if [ $ZCASH_NETWORK_ENVIRONMENT = "$ZCASH_MAINNET" ]
then
touch $ZCASH_LIB_RUST_BUILD_PATH/$ZCASH_BUILD_TYPE_MAINNET_FLAG
elif [[ "$ZCASH_NETWORK_ENVIRONMENT" = "$ZCASH_TESTNET" ]]
then
touch $ZCASH_LIB_RUST_BUILD_PATH/$ZCASH_BUILD_TYPE_TESTNET_FLAG
fi
}

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'ZcashLightClientKit' s.name = 'ZcashLightClientKit'
s.version = '0.12.0-alpha.10' s.version = '0.12.0-alpha.12'
s.summary = 'Zcash Light Client wallet SDK for iOS' s.summary = 'Zcash Light Client wallet SDK for iOS'
s.description = <<-DESC s.description = <<-DESC
@ -30,11 +30,9 @@ Pod::Spec.new do |s|
s.script_phase = { s.script_phase = {
:name => 'Build generate constants and build librustzcash', :name => 'Build generate constants and build librustzcash',
:script => 'sh ${PODS_TARGET_SRCROOT}/Scripts/generate_zcashsdk_constants.sh && sh ${PODS_TARGET_SRCROOT}/Scripts/build_librustzcash_xcode.sh', :script => 'sh ${PODS_TARGET_SRCROOT}/Scripts/build_librustzcash_xcode.sh',
:execution_position => :before_compile, :execution_position => :before_compile,
:output_files => [
'${PODS_TARGET_SRCROOT}/ZcashLightClientKit/Generated/WalletBirthday+saplingtree.generated.swift',
'${PODS_TARGET_SRCROOT}/ZcashLightClientKit/Generated/ZcashSDK.generated.swift']
} }
s.test_spec 'Tests' do | test_spec | s.test_spec 'Tests' do | test_spec |
@ -42,7 +40,7 @@ Pod::Spec.new do |s|
test_spec.ios.resources = 'ZcashLightClientKitTests/**/*.{db,params}' test_spec.ios.resources = 'ZcashLightClientKitTests/**/*.{db,params}'
test_spec.script_phase = { test_spec.script_phase = {
:name => 'Build generate constants and build librustzcash', :name => 'Build generate constants and build librustzcash',
:script => 'sh ${PODS_TARGET_SRCROOT}/Scripts/generate_test_constants.sh && ${PODS_TARGET_SRCROOT}/Scripts/build_librustzcash_xcode.sh --testing', :script => 'sh ${PODS_TARGET_SRCROOT}/Scripts/generate_test_constants.sh && ${PODS_TARGET_SRCROOT}/Scripts/build_librustzcash_xcode.sh',
:execution_position => :before_compile :execution_position => :before_compile
} }
test_spec.dependency 'gRPC-Swift', '= 1.0.0' test_spec.dependency 'gRPC-Swift', '= 1.0.0'
@ -53,7 +51,7 @@ Pod::Spec.new do |s|
test_spec.source_files = 'DerivationToolTests/**/*.{swift}' test_spec.source_files = 'DerivationToolTests/**/*.{swift}'
test_spec.script_phase = { test_spec.script_phase = {
:name => 'Build generate constants and build librustzcash', :name => 'Build generate constants and build librustzcash',
:script => 'sh ${PODS_TARGET_SRCROOT}/Scripts/generate_test_constants.sh && ${PODS_TARGET_SRCROOT}/Scripts/build_librustzcash_xcode.sh --testing', :script => 'sh ${PODS_TARGET_SRCROOT}/Scripts/generate_test_constants.sh && ${PODS_TARGET_SRCROOT}/Scripts/build_librustzcash_xcode.sh',
:execution_position => :before_compile :execution_position => :before_compile
} }
test_spec.dependency 'gRPC-Swift', '= 1.0.0' test_spec.dependency 'gRPC-Swift', '= 1.0.0'

View File

@ -25,13 +25,15 @@ class MigrationManager {
var cacheDb: ConnectionProvider var cacheDb: ConnectionProvider
var dataDb: ConnectionProvider var dataDb: ConnectionProvider
var pendingDb: ConnectionProvider var pendingDb: ConnectionProvider
var network: NetworkType
init(cacheDbConnection: ConnectionProvider, init(cacheDbConnection: ConnectionProvider,
dataDbConnection: ConnectionProvider, dataDbConnection: ConnectionProvider,
pendingDbConnection: ConnectionProvider) { pendingDbConnection: ConnectionProvider,
networkType: NetworkType) {
self.cacheDb = cacheDbConnection self.cacheDb = cacheDbConnection
self.dataDb = dataDbConnection self.dataDb = dataDbConnection
self.pendingDb = pendingDbConnection self.pendingDb = pendingDbConnection
self.network = networkType
} }
static let latestDataDbMigrationVersion: Int32 = DataDbMigrations.version1.rawValue static let latestDataDbMigrationVersion: Int32 = DataDbMigrations.version1.rawValue
@ -149,7 +151,7 @@ class MigrationManager {
LoggerProxy.debug(message) LoggerProxy.debug(message)
throw StorageError.migrationFailedWithMessage(message: message) throw StorageError.migrationFailedWithMessage(message: message)
} }
let derivationTool = DerivationTool.default let derivationTool = DerivationTool(networkType: self.network)
for tuple in zip(accounts, viewingKeys) { for tuple in zip(accounts, viewingKeys) {
let tAddr = try derivationTool.deriveTransparentAddressFromPublicKey(tuple.1.extpub) let tAddr = try derivationTool.deriveTransparentAddressFromPublicKey(tuple.1.extpub)
@ -177,7 +179,9 @@ class MigrationManager {
return return
} }
let uvks = try DerivationTool.default.deriveUnifiedViewingKeysFromSeed(seedBytes, numberOfAccounts: accounts.count) let derivationTool = DerivationTool(networkType: self.network)
let uvks = try derivationTool.deriveUnifiedViewingKeysFromSeed(seedBytes, numberOfAccounts: accounts.count)
try performVersion1Migration(viewingKeys: uvks) try performVersion1Migration(viewingKeys: uvks)
} }

View File

@ -90,9 +90,6 @@ class CompactBlockStreamDownloadOperation: ZcashOperation {
} }
let latestDownloaded = try storage.latestHeight() let latestDownloaded = try storage.latestHeight()
let startHeight = max(self.startHeight ?? BlockHeight.empty(), latestDownloaded) let startHeight = max(self.startHeight ?? BlockHeight.empty(), latestDownloaded)
guard startHeight >= ZcashSDK.SAPLING_ACTIVATION_HEIGHT else {
throw CompactBlockStreamDownloadOperationError.startHeightMissing
}
self.cancelable = self.service.blockStream(startHeight: startHeight, endHeight: latestHeight) { [weak self] result in self.cancelable = self.service.blockStream(startHeight: startHeight, endHeight: latestHeight) { [weak self] result in
switch result { switch result {
@ -106,7 +103,11 @@ class CompactBlockStreamDownloadOperation: ZcashOperation {
self?.fail(error: e) self?.fail(error: e)
} }
case .failure(let e): case .failure(let e):
self?.fail(error: e) if case .userCancelled = e {
self?.done = true
} else {
self?.fail(error: e)
}
} }
} handler: {[weak self] block in } handler: {[weak self] block in
@ -181,16 +182,14 @@ class CompactBlockBatchDownloadOperation: ZcashOperation {
} }
self.startedHandler?() self.startedHandler?()
do { do {
let localDownloadedHeight = try self.storage.latestHeight()
guard startHeight >= ZcashSDK.SAPLING_ACTIVATION_HEIGHT else { if localDownloadedHeight != BlockHeight.empty() && localDownloadedHeight > startHeight {
throw CompactBlockBatchDownloadOperationError.startHeightMissing
}
var localDownloadedHeight = try self.storage.latestHeight()
if localDownloadedHeight != startHeight {
LoggerProxy.warn("provided startHeight (\(startHeight)) differs from local latest downloaded height (\(localDownloadedHeight))") LoggerProxy.warn("provided startHeight (\(startHeight)) differs from local latest downloaded height (\(localDownloadedHeight))")
startHeight = localDownloadedHeight + 1 startHeight = localDownloadedHeight + 1
} }
var currentHeight = startHeight var currentHeight = startHeight
self.progressDelegate?.progressUpdated(.download(BlockProgress(startHeight: currentHeight, targetHeight: targetHeight, progressHeight: currentHeight))) self.progressDelegate?.progressUpdated(.download(BlockProgress(startHeight: currentHeight, targetHeight: targetHeight, progressHeight: currentHeight)))

View File

@ -24,6 +24,7 @@ class CompactBlockEnhancementOperation: ZcashOperation {
var repository: TransactionRepository var repository: TransactionRepository
var maxRetries: Int = 5 var maxRetries: Int = 5
var retries: Int = 0 var retries: Int = 0
private(set) var network: NetworkType
weak var progressDelegate: CompactBlockProgressDelegate? weak var progressDelegate: CompactBlockProgressDelegate?
private var dataDb: URL private var dataDb: URL
@ -34,6 +35,7 @@ class CompactBlockEnhancementOperation: ZcashOperation {
downloader: CompactBlockDownloading, downloader: CompactBlockDownloading,
repository: TransactionRepository, repository: TransactionRepository,
range: BlockRange, range: BlockRange,
networkType: NetworkType,
progressDelegate: CompactBlockProgressDelegate? = nil) { progressDelegate: CompactBlockProgressDelegate? = nil) {
rustBackend = rustWelding rustBackend = rustWelding
self.dataDb = dataDb self.dataDb = dataDb
@ -41,6 +43,7 @@ class CompactBlockEnhancementOperation: ZcashOperation {
self.repository = repository self.repository = repository
self.range = range self.range = range
self.progressDelegate = progressDelegate self.progressDelegate = progressDelegate
self.network = networkType
super.init() super.init()
} }
@ -112,7 +115,7 @@ class CompactBlockEnhancementOperation: ZcashOperation {
throw error throw error
} }
guard rustBackend.decryptAndStoreTransaction(dbData: dataDb, tx: rawBytes) else { guard rustBackend.decryptAndStoreTransaction(dbData: dataDb, tx: rawBytes, networkType: network) else {
if let rustError = rustBackend.lastError() { if let rustError = rustBackend.lastError() {
throw EnhancementError.decryptError(error: rustError) throw EnhancementError.decryptError(error: rustError)
} }

View File

@ -27,7 +27,7 @@ public enum CompactBlockProcessorError: Error {
case criticalError case criticalError
case invalidAccount case invalidAccount
case wrongConsensusBranchId(expectedLocally: ConsensusBranchID, found: ConsensusBranchID) case wrongConsensusBranchId(expectedLocally: ConsensusBranchID, found: ConsensusBranchID)
case networkMismatch(expected: ZcashSDK.NetworkType, found: ZcashSDK.NetworkType) case networkMismatch(expected: NetworkType, found: NetworkType)
case saplingActivationMismatch(expected: BlockHeight, found: BlockHeight) case saplingActivationMismatch(expected: BlockHeight, found: BlockHeight)
} }
/** /**
@ -228,20 +228,23 @@ public class CompactBlockProcessor {
public var maxBackoffInterval = ZcashSDK.DEFAULT_MAX_BACKOFF_INTERVAL public var maxBackoffInterval = ZcashSDK.DEFAULT_MAX_BACKOFF_INTERVAL
public var rewindDistance = ZcashSDK.DEFAULT_REWIND_DISTANCE public var rewindDistance = ZcashSDK.DEFAULT_REWIND_DISTANCE
public var walletBirthday: BlockHeight public var walletBirthday: BlockHeight
private(set) var network: ZcashNetwork
private(set) var saplingActivation: BlockHeight private(set) var saplingActivation: BlockHeight
init ( init (
cacheDb: URL, cacheDb: URL,
dataDb: URL, dataDb: URL,
downloadBatchSize: Int, downloadBatchSize: Int,
retries: Int, retries: Int,
maxBackoffInterval: TimeInterval, maxBackoffInterval: TimeInterval,
rewindDistance: Int, rewindDistance: Int,
walletBirthday: BlockHeight, walletBirthday: BlockHeight,
saplingActivation: BlockHeight saplingActivation: BlockHeight,
network: ZcashNetwork
) { ) {
self.cacheDb = cacheDb self.cacheDb = cacheDb
self.dataDb = dataDb self.dataDb = dataDb
self.network = network
self.downloadBatchSize = downloadBatchSize self.downloadBatchSize = downloadBatchSize
self.retries = retries self.retries = retries
self.maxBackoffInterval = maxBackoffInterval self.maxBackoffInterval = maxBackoffInterval
@ -250,11 +253,12 @@ public class CompactBlockProcessor {
self.saplingActivation = saplingActivation self.saplingActivation = saplingActivation
} }
public init(cacheDb: URL, dataDb: URL, walletBirthday: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT){ public init(cacheDb: URL, dataDb: URL, walletBirthday: BlockHeight, network: ZcashNetwork){
self.cacheDb = cacheDb self.cacheDb = cacheDb
self.dataDb = dataDb self.dataDb = dataDb
self.walletBirthday = walletBirthday self.walletBirthday = walletBirthday
self.saplingActivation = ZcashSDK.SAPLING_ACTIVATION_HEIGHT self.saplingActivation = network.constants.SAPLING_ACTIVATION_HEIGHT
self.network = network
} }
} }
/** /**
@ -313,7 +317,7 @@ public class CompactBlockProcessor {
private var transactionRepository: TransactionRepository private var transactionRepository: TransactionRepository
private var accountRepository: AccountRepository private var accountRepository: AccountRepository
private var rustBackend: ZcashRustBackendWelding.Type private var rustBackend: ZcashRustBackendWelding.Type
var config: Configuration = Configuration.standard { var config: Configuration {
willSet { willSet {
self.stop() self.stop()
} }
@ -348,7 +352,7 @@ public class CompactBlockProcessor {
- Throws CompactBlockProcessorError.invalidConfiguration if block height is invalid or if processor is already started - Throws CompactBlockProcessorError.invalidConfiguration if block height is invalid or if processor is already started
*/ */
func setStartHeight(_ startHeight: BlockHeight) throws { func setStartHeight(_ startHeight: BlockHeight) throws {
guard self.state == .stopped, startHeight >= ZcashSDK.SAPLING_ACTIVATION_HEIGHT else { guard self.state == .stopped, startHeight >= config.network.constants.SAPLING_ACTIVATION_HEIGHT else {
throw CompactBlockProcessorError.invalidConfiguration throw CompactBlockProcessorError.invalidConfiguration
} }
@ -387,7 +391,8 @@ public class CompactBlockProcessor {
backend: initializer.rustBackend, backend: initializer.rustBackend,
config: Configuration(cacheDb: initializer.cacheDbURL, config: Configuration(cacheDb: initializer.cacheDbURL,
dataDb: initializer.dataDbURL, dataDb: initializer.dataDbURL,
walletBirthday: initializer.walletBirthday.height), walletBirthday: initializer.walletBirthday.height,
network: initializer.network),
repository: initializer.transactionRepository, repository: initializer.transactionRepository,
accountRepository: initializer.accountRepository) accountRepository: initializer.accountRepository)
} }
@ -493,6 +498,7 @@ public class CompactBlockProcessor {
do { do {
try Self.validateServerInfo(info, try Self.validateServerInfo(info,
saplingActivation: self.config.saplingActivation, saplingActivation: self.config.saplingActivation,
localNetwork: self.config.network,
rustBackend: self.rustBackend) rustBackend: self.rustBackend)
completionBlock() completionBlock()
} catch { } catch {
@ -507,15 +513,16 @@ public class CompactBlockProcessor {
static func validateServerInfo(_ info: LightWalletdInfo, static func validateServerInfo(_ info: LightWalletdInfo,
saplingActivation: BlockHeight, saplingActivation: BlockHeight,
localNetwork: ZcashNetwork,
rustBackend: ZcashRustBackendWelding.Type) throws { rustBackend: ZcashRustBackendWelding.Type) throws {
// check network types // check network types
guard let remoteNetworkType = ZcashSDK.NetworkType(info.chainName) else { guard let remoteNetworkType = NetworkType.forChainName(info.chainName) else {
throw CompactBlockProcessorError.generalError(message: "Chain name does not match. Expected either 'test' or 'main' but received '\(info.chainName)'. this is probably an API or programming error") throw CompactBlockProcessorError.generalError(message: "Chain name does not match. Expected either 'test' or 'main' but received '\(info.chainName)'. this is probably an API or programming error")
} }
guard remoteNetworkType == ZcashSDK.networkType else { guard remoteNetworkType == localNetwork.networkType else {
throw CompactBlockProcessorError.networkMismatch(expected: ZcashSDK.networkType, found: remoteNetworkType) throw CompactBlockProcessorError.networkMismatch(expected: localNetwork.networkType, found: remoteNetworkType)
} }
guard saplingActivation == info.saplingActivationHeight else { guard saplingActivation == info.saplingActivationHeight else {
@ -523,7 +530,7 @@ public class CompactBlockProcessor {
} }
// check branch id // check branch id
let localBranch = try rustBackend.consensusBranchIdFor(height: Int32(info.blockHeight)) let localBranch = try rustBackend.consensusBranchIdFor(height: Int32(info.blockHeight), networkType: localNetwork.networkType)
guard let remoteBranchID = ConsensusBranchID.fromString(info.consensusBranchID) guard let remoteBranchID = ConsensusBranchID.fromString(info.consensusBranchID)
else { else {
@ -564,7 +571,7 @@ public class CompactBlockProcessor {
let lastDownloaded = try downloader.lastDownloadedBlockHeight() let lastDownloaded = try downloader.lastDownloadedBlockHeight()
let height = Int32(height ?? lastDownloaded) let height = Int32(height ?? lastDownloaded)
let nearestHeight = rustBackend.getNearestRewindHeight(dbData: config.dataDb, height: height) let nearestHeight = rustBackend.getNearestRewindHeight(dbData: config.dataDb, height: height, networkType: self.config.network.networkType)
guard nearestHeight > 0 else { guard nearestHeight > 0 else {
let error = rustBackend.lastError() ?? RustWeldingError.genericError(message: "unknown error getting nearest rewind height for height: \(height)") let error = rustBackend.lastError() ?? RustWeldingError.genericError(message: "unknown error getting nearest rewind height for height: \(height)")
@ -574,7 +581,7 @@ public class CompactBlockProcessor {
// FIXME: this should be done on the rust layer // FIXME: this should be done on the rust layer
let rewindHeight = max(Int32(nearestHeight - 1) , Int32(config.walletBirthday)) let rewindHeight = max(Int32(nearestHeight - 1) , Int32(config.walletBirthday))
guard rustBackend.rewindToHeight(dbData: config.dataDb, height: rewindHeight) else { guard rustBackend.rewindToHeight(dbData: config.dataDb, height: rewindHeight, networkType: self.config.network.networkType) else {
let error = rustBackend.lastError() ?? RustWeldingError.genericError(message: "unknown error rewinding to height \(height)") let error = rustBackend.lastError() ?? RustWeldingError.genericError(message: "unknown error rewinding to height \(height)")
fail(error) fail(error)
throw error throw error
@ -649,7 +656,7 @@ public class CompactBlockProcessor {
} }
} }
let validateChainOperation = CompactBlockValidationOperation(rustWelding: self.rustBackend, cacheDb: cfg.cacheDb, dataDb: cfg.dataDb) let validateChainOperation = CompactBlockValidationOperation(rustWelding: self.rustBackend, cacheDb: cfg.cacheDb, dataDb: cfg.dataDb, networkType: self.config.network.networkType)
let downloadValidateAdapterOperation = BlockOperation { [weak validateChainOperation, weak downloadBlockOperation] in let downloadValidateAdapterOperation = BlockOperation { [weak validateChainOperation, weak downloadBlockOperation] in
validateChainOperation?.error = downloadBlockOperation?.error validateChainOperation?.error = downloadBlockOperation?.error
@ -698,7 +705,7 @@ public class CompactBlockProcessor {
} }
} }
let scanBlocksOperation = CompactBlockBatchScanningOperation(rustWelding: rustBackend, cacheDb: config.cacheDb, dataDb: config.dataDb, transactionRepository: transactionRepository, range: range, progressDelegate: self) let scanBlocksOperation = CompactBlockBatchScanningOperation(rustWelding: rustBackend, cacheDb: config.cacheDb, dataDb: config.dataDb, transactionRepository: transactionRepository, range: range, networkType: self.config.network.networkType, progressDelegate: self)
let validateScanningAdapterOperation = BlockOperation { [weak scanBlocksOperation, weak validateChainOperation] in let validateScanningAdapterOperation = BlockOperation { [weak scanBlocksOperation, weak validateChainOperation] in
scanBlocksOperation?.error = validateChainOperation?.error scanBlocksOperation?.error = validateChainOperation?.error
@ -727,7 +734,7 @@ public class CompactBlockProcessor {
} }
} }
let enhanceOperation = CompactBlockEnhancementOperation(rustWelding: rustBackend, dataDb: config.dataDb, downloader: downloader, repository: transactionRepository, range: range.blockRange()) let enhanceOperation = CompactBlockEnhancementOperation(rustWelding: rustBackend, dataDb: config.dataDb, downloader: downloader, repository: transactionRepository, range: range.blockRange(), networkType: self.config.network.networkType)
enhanceOperation.startedHandler = { enhanceOperation.startedHandler = {
LoggerProxy.debug("Started Enhancing range: \(range)") LoggerProxy.debug("Started Enhancing range: \(range)")
@ -760,7 +767,7 @@ public class CompactBlockProcessor {
enhanceOperation?.error = scanBlocksOperation?.error enhanceOperation?.error = scanBlocksOperation?.error
} }
let fetchOperation = FetchUnspentTxOutputsOperation(accountRepository: accountRepository, downloader: self.downloader, rustbackend: rustBackend, dataDb: config.dataDb, startHeight: config.walletBirthday) let fetchOperation = FetchUnspentTxOutputsOperation(accountRepository: accountRepository, downloader: self.downloader, rustbackend: rustBackend, dataDb: config.dataDb, startHeight: config.walletBirthday, networkType: self.config.network.networkType)
fetchOperation.startedHandler = { [weak self] in fetchOperation.startedHandler = { [weak self] in
DispatchQueue.main.async { [weak self] in DispatchQueue.main.async { [weak self] in
@ -855,7 +862,7 @@ public class CompactBlockProcessor {
// rewind // rewind
let rewindHeight = determineLowerBound(errorHeight: height, consecutiveErrors: consecutiveChainValidationErrors, walletBirthday: self.config.walletBirthday) let rewindHeight = determineLowerBound(errorHeight: height, consecutiveErrors: consecutiveChainValidationErrors, walletBirthday: self.config.walletBirthday)
guard rustBackend.rewindToHeight(dbData: config.dataDb, height: Int32(rewindHeight)) else { guard rustBackend.rewindToHeight(dbData: config.dataDb, height: Int32(rewindHeight), networkType: self.config.network.networkType) else {
fail(rustBackend.lastError() ?? RustWeldingError.genericError(message: "unknown error rewinding to height \(height)")) fail(rustBackend.lastError() ?? RustWeldingError.genericError(message: "unknown error rewinding to height \(height)"))
return return
} }
@ -1053,9 +1060,12 @@ public extension CompactBlockProcessor.Configuration {
/** /**
Standard configuration for most compact block processors Standard configuration for most compact block processors
*/ */
static var standard: CompactBlockProcessor.Configuration { static func standard(for network: ZcashNetwork, walletBirthday: BlockHeight) -> CompactBlockProcessor.Configuration {
let pathProvider = DefaultResourceProvider() let pathProvider = DefaultResourceProvider(network: network)
return CompactBlockProcessor.Configuration(cacheDb: pathProvider.cacheDbURL, dataDb: pathProvider.dataDbURL) return CompactBlockProcessor.Configuration(cacheDb: pathProvider.cacheDbURL,
dataDb: pathProvider.dataDbURL,
walletBirthday: walletBirthday,
network: network)
} }
} }
@ -1103,7 +1113,7 @@ extension CompactBlockProcessor.State: Equatable {
extension CompactBlockProcessor { extension CompactBlockProcessor {
public func utxoCacheBalance(tAddress: String) throws -> WalletBalance { public func utxoCacheBalance(tAddress: String) throws -> WalletBalance {
try rustBackend.downloadedUtxoBalance(dbData: config.dataDb, address: tAddress) try rustBackend.downloadedUtxoBalance(dbData: config.dataDb, address: tAddress, networkType: config.network.networkType)
} }
} }
@ -1163,7 +1173,7 @@ extension CompactBlockProcessor {
guard let self = self else { return } guard let self = self else { return }
do { do {
guard try self.rustBackend.clearUtxos(dbData: dataDb, address: tAddress, sinceHeight: startHeight - 1) >= 0 else { guard try self.rustBackend.clearUtxos(dbData: dataDb, address: tAddress, sinceHeight: startHeight - 1, networkType: self.config.network.networkType) >= 0 else {
result(.failure(CompactBlockProcessorError.generalError(message: "attempted to clear utxos but -1 was returned"))) result(.failure(CompactBlockProcessorError.generalError(message: "attempted to clear utxos but -1 was returned")))
return return
} }
@ -1191,7 +1201,8 @@ extension CompactBlockProcessor {
index: utxo.index, index: utxo.index,
script: utxo.script.bytes, script: utxo.script.bytes,
value: Int64(utxo.valueZat), value: Int64(utxo.valueZat),
height: utxo.height) ? refreshed.append(utxo) : skipped.append(utxo) height: utxo.height,
networkType: self.config.network.networkType) ? refreshed.append(utxo) : skipped.append(utxo)
} catch { } catch {
LoggerProxy.info("failed to put utxo - error: \(error)") LoggerProxy.info("failed to put utxo - error: \(error)")
skipped.append(utxo) skipped.append(utxo)
@ -1305,7 +1316,7 @@ extension CompactBlockProcessor {
let info = try service.getInfo() let info = try service.getInfo()
try CompactBlockProcessor.validateServerInfo(info, saplingActivation: config.saplingActivation, rustBackend: rustBackend) try CompactBlockProcessor.validateServerInfo(info, saplingActivation: config.saplingActivation, localNetwork: config.network, rustBackend: rustBackend)
// get latest block height // get latest block height
let latestDownloadedBlockHeight: BlockHeight = max(config.walletBirthday,try downloader.lastDownloadedBlockHeight()) let latestDownloadedBlockHeight: BlockHeight = max(config.walletBirthday,try downloader.lastDownloadedBlockHeight())
@ -1323,4 +1334,3 @@ extension CompactBlockProcessor {
} }
} }
} }

View File

@ -19,11 +19,13 @@ class CompactBlockScanningOperation: ZcashOperation {
private var cacheDb: URL private var cacheDb: URL
private var dataDb: URL private var dataDb: URL
private var limit: UInt32 private var limit: UInt32
init(rustWelding: ZcashRustBackendWelding.Type, cacheDb: URL, dataDb: URL, limit: UInt32 = 0) { private var network: NetworkType
init(rustWelding: ZcashRustBackendWelding.Type, cacheDb: URL, dataDb: URL, limit: UInt32 = 0, networkType: NetworkType) {
rustBackend = rustWelding rustBackend = rustWelding
self.cacheDb = cacheDb self.cacheDb = cacheDb
self.dataDb = dataDb self.dataDb = dataDb
self.limit = limit self.limit = limit
self.network = networkType
super.init() super.init()
} }
@ -33,7 +35,7 @@ class CompactBlockScanningOperation: ZcashOperation {
return return
} }
self.startedHandler?() self.startedHandler?()
guard self.rustBackend.scanBlocks(dbCache: self.cacheDb, dbData: self.dataDb, limit: limit) else { guard self.rustBackend.scanBlocks(dbCache: self.cacheDb, dbData: self.dataDb, limit: limit, networkType: network) else {
self.error = self.rustBackend.lastError() ?? ZcashOperationError.unknown self.error = self.rustBackend.lastError() ?? ZcashOperationError.unknown
LoggerProxy.debug("block scanning failed with error: \(String(describing: self.error))") LoggerProxy.debug("block scanning failed with error: \(String(describing: self.error))")
self.fail() self.fail()
@ -112,6 +114,7 @@ class CompactBlockBatchScanningOperation: ZcashOperation {
private var batchSize: UInt32 private var batchSize: UInt32
private var blockRange: CompactBlockRange private var blockRange: CompactBlockRange
private var transactionRepository: TransactionRepository private var transactionRepository: TransactionRepository
private var network: NetworkType
init(rustWelding: ZcashRustBackendWelding.Type, init(rustWelding: ZcashRustBackendWelding.Type,
cacheDb: URL, cacheDb: URL,
@ -119,6 +122,7 @@ class CompactBlockBatchScanningOperation: ZcashOperation {
transactionRepository: TransactionRepository, transactionRepository: TransactionRepository,
range: CompactBlockRange, range: CompactBlockRange,
batchSize: UInt32 = 100, batchSize: UInt32 = 100,
networkType: NetworkType,
progressDelegate: CompactBlockProgressDelegate? = nil) { progressDelegate: CompactBlockProgressDelegate? = nil) {
rustBackend = rustWelding rustBackend = rustWelding
self.cacheDb = cacheDb self.cacheDb = cacheDb
@ -127,6 +131,7 @@ class CompactBlockBatchScanningOperation: ZcashOperation {
self.blockRange = range self.blockRange = range
self.batchSize = batchSize self.batchSize = batchSize
self.progressDelegate = progressDelegate self.progressDelegate = progressDelegate
self.network = networkType
super.init() super.init()
} }
@ -139,7 +144,7 @@ class CompactBlockBatchScanningOperation: ZcashOperation {
do { do {
if batchSize == 0 { if batchSize == 0 {
let scanStartTime = Date() let scanStartTime = Date()
guard self.rustBackend.scanBlocks(dbCache: self.cacheDb, dbData: self.dataDb, limit: batchSize) else { guard self.rustBackend.scanBlocks(dbCache: self.cacheDb, dbData: self.dataDb, limit: batchSize, networkType: network) else {
self.scanFailed(self.rustBackend.lastError() ?? ZcashOperationError.unknown) self.scanFailed(self.rustBackend.lastError() ?? ZcashOperationError.unknown)
return return
} }
@ -164,7 +169,10 @@ class CompactBlockBatchScanningOperation: ZcashOperation {
} }
let previousScannedHeight = lastScannedHeight let previousScannedHeight = lastScannedHeight
let scanStartTime = Date() let scanStartTime = Date()
guard self.rustBackend.scanBlocks(dbCache: self.cacheDb, dbData: self.dataDb, limit: batchSize) else { guard self.rustBackend.scanBlocks(dbCache: self.cacheDb,
dbData: self.dataDb,
limit: batchSize,
networkType: network) else {
self.scanFailed(self.rustBackend.lastError() ?? ZcashOperationError.unknown) self.scanFailed(self.rustBackend.lastError() ?? ZcashOperationError.unknown)
return return
} }

View File

@ -22,11 +22,16 @@ class CompactBlockValidationOperation: ZcashOperation {
private var cacheDb: URL private var cacheDb: URL
private var dataDb: URL private var dataDb: URL
private var network: NetworkType
init(rustWelding: ZcashRustBackendWelding.Type, cacheDb: URL, dataDb: URL) { init(rustWelding: ZcashRustBackendWelding.Type,
cacheDb: URL,
dataDb: URL,
networkType: NetworkType) {
rustBackend = rustWelding rustBackend = rustWelding
self.cacheDb = cacheDb self.cacheDb = cacheDb
self.dataDb = dataDb self.dataDb = dataDb
self.network = networkType
super.init() super.init()
} }
@ -36,7 +41,7 @@ class CompactBlockValidationOperation: ZcashOperation {
return return
} }
self.startedHandler?() self.startedHandler?()
let result = self.rustBackend.validateCombinedChain(dbCache: cacheDb, dbData: dataDb) let result = self.rustBackend.validateCombinedChain(dbCache: cacheDb, dbData: dataDb, networkType: self.network)
switch result { switch result {
case 0: case 0:
let error = CompactBlockValidationError.failedWithError(rustBackend.lastError()) let error = CompactBlockValidationError.failedWithError(rustBackend.lastError())

View File

@ -22,18 +22,21 @@ class FetchUnspentTxOutputsOperation: ZcashOperation {
private var downloader: CompactBlockDownloading private var downloader: CompactBlockDownloading
private var rustbackend: ZcashRustBackendWelding.Type private var rustbackend: ZcashRustBackendWelding.Type
private var startHeight: BlockHeight private var startHeight: BlockHeight
private var network: NetworkType
private var dataDb: URL private var dataDb: URL
init(accountRepository: AccountRepository, init(accountRepository: AccountRepository,
downloader: CompactBlockDownloading, downloader: CompactBlockDownloading,
rustbackend: ZcashRustBackendWelding.Type, rustbackend: ZcashRustBackendWelding.Type,
dataDb: URL, dataDb: URL,
startHeight: BlockHeight) { startHeight: BlockHeight,
networkType: NetworkType) {
self.dataDb = dataDb self.dataDb = dataDb
self.accountRepository = accountRepository self.accountRepository = accountRepository
self.downloader = downloader self.downloader = downloader
self.rustbackend = rustbackend self.rustbackend = rustbackend
self.startHeight = startHeight self.startHeight = startHeight
self.network = networkType
} }
override func main() { override func main() {
@ -46,7 +49,10 @@ class FetchUnspentTxOutputsOperation: ZcashOperation {
let tAddresses = try accountRepository.getAll().map({ $0.transparentAddress }) let tAddresses = try accountRepository.getAll().map({ $0.transparentAddress })
do { do {
for tAddress in tAddresses { for tAddress in tAddresses {
guard try self.rustbackend.clearUtxos(dbData: dataDb, address: tAddress, sinceHeight: startHeight - 1) >= 0 else { guard try self.rustbackend.clearUtxos(dbData: dataDb,
address: tAddress,
sinceHeight: startHeight - 1,
networkType: network) >= 0 else {
let rustError = rustbackend.lastError() ?? RustWeldingError.genericError(message: "attempted to clear utxos but -1 was returned") let rustError = rustbackend.lastError() ?? RustWeldingError.genericError(message: "attempted to clear utxos but -1 was returned")
throw rustError throw rustError
@ -80,7 +86,8 @@ class FetchUnspentTxOutputsOperation: ZcashOperation {
index: utxo.index, index: utxo.index,
script: utxo.script.bytes, script: utxo.script.bytes,
value: Int64(utxo.valueZat), value: Int64(utxo.valueZat),
height: utxo.height) ? refreshed.append(utxo) : skipped.append(utxo) height: utxo.height,
networkType: network) ? refreshed.append(utxo) : skipped.append(utxo)
} catch { } catch {
LoggerProxy.error("failed to put utxo - error: \(error)") LoggerProxy.error("failed to put utxo - error: \(error)")
skipped.append(utxo) skipped.append(utxo)

View File

@ -0,0 +1,19 @@
//
// WalletBirthday+Constants.swift
// ZcashLightClientKit
//
// Created by Francisco Gindre on 7/28/21.
//
import Foundation
public extension WalletBirthday {
static func birthday(with height: BlockHeight, network: ZcashNetwork) -> WalletBirthday {
switch network.networkType {
case .mainnet:
return mainnetBirthday(with: height)
case .testnet:
return testnetBirthday(with: height)
}
}
}

View File

@ -0,0 +1,498 @@
//
// WalletBirthday+mainnet.swift
// ZcashLightClientKit
//
// Created by Francisco Gindre on 7/28/21.
//
import Foundation
extension WalletBirthday {
static func mainnetBirthday(with height: BlockHeight) -> WalletBirthday {
switch height {
case BlockHeight.min ..< 640_000:
return WalletBirthday(
height: 419_200,
hash: "00000000025a57200d898ac7f21e26bf29028bbe96ec46e05b2c17cc9db9e4f3",
time: 1540779337,
tree: "000000"
)
case 640_000 ..< 643_500:
return WalletBirthday(
height: 640000,
hash: "00000000016cd930734753f5acce6274b391f14330c793e54e7bd9f942d17114",
time: 1574051743,
tree: "0165aed8451b6a6c0a66294267976be6d171f2acf83c2b5b94d976cb32062cfa6301cd5b1e5ce12e7d82d07c1b83f7746ef2be8d0c56f90f82b71a1e422a1ffb400710000142f5056f23557ba4cbc562067d43fdc07477fa740c6a13a4ed6d0667b7c1b5510000000001ee9dbe0b8d268efe7e8a88ae7b0ac91923bd71ee81bba0e35e3b9504be59aa250001a2178e94504352c0dd7d6f711b814f8a332239f688568f1719808fd1d385831e0001967ca804f328397d98bd5e1f36786a9d44b06192e70a38026909fb4ce251943e000001fa6980c053d84f809b6abcf35690f03a11f87b28e3240828e32e3f57af41e54e01319312241b0031e3a255b0d708750b4cb3f3fe79e3503fe488cc8db1dd00753801754bb593ea42d231a7ddf367640f09bbf59dc00f2c1d2003cc340e0c016b5b13"
)
case 643_500 ..< 663000:
return WalletBirthday(
height: 643_500,
hash: "000000000041005fd724ff6e29bd1738bed69a4d9ca028e124029525350bd789",
time: 1574579149,
tree: "01999fc372390699b15f71d41745abe6a2ea0db4ffa8894d3c5fe30b9261a1a43a01585112668685bd6783cb01b72d17dc86c6d740c27cccf66b75e959e4e4f5ea3710019b7f6b4457a97eadbe1a39bfcc6ba0a56d37010d0d799e1e652fc29733103e04016a0b4d2705e1feb2021d80e5785608536dde05aea5ef676a5427244228b19e2d00010973d03ad5f79fcac64ab3ffbdaaac1a24b74a3617770bf960fb004cbd422439000001984bfce9361025cc38574f944a3ed7b074b3bf88cfce6f14c4a9be4d91d6dc730105871ec1e3737a39bceb00b0c2d253ff36f472e92c361e7ef360d49ea8dc4c4200000001c145105e1bf401668a8f23ca70c47ee92d23bd366072020c83d26b855eeafd6d0001fa6980c053d84f809b6abcf35690f03a11f87b28e3240828e32e3f57af41e54e01319312241b0031e3a255b0d708750b4cb3f3fe79e3503fe488cc8db1dd00753801754bb593ea42d231a7ddf367640f09bbf59dc00f2c1d2003cc340e0c016b5b13"
)
case 663000 ..< 663150:
return WalletBirthday(
height: 663000,
hash: "0000000000bd422264b700bb33cab167ab42392c89db0e7c8ce30d57f346fe69",
time: 1576810013,
tree: "0102f02a8cd23e35502f8efa55893c7a145168ac3fa00d4bd032b55097bbe0335a01b57c362e3c834f2216c72ae0d8a335fd2397cc80073d0f5b29c419028bc6c94c100000000157bfd70afa37c8bf0c60c9e160d2145bdfbcf07837b0ff90bf8a5108722cc85400000000011bc9521263584de20822f9483e7edb5af54150c4823c775b2efc6a1eded9625501a6030f8d4b588681eddb66cad63f09c5c7519db49500fc56ebd481ce5e903c22000163f4eec5a2fe00a5f45e71e1542ff01e937d2210c99f03addcce5314a5278b2d0163ab01f46a3bb6ea46f5a19d5bdd59eb3f81e19cfa6d10ab0fd5566c7a16992601fa6980c053d84f809b6abcf35690f03a11f87b28e3240828e32e3f57af41e54e01319312241b0031e3a255b0d708750b4cb3f3fe79e3503fe488cc8db1dd00753801754bb593ea42d231a7ddf367640f09bbf59dc00f2c1d2003cc340e0c016b5b13"
)
case 663150 ..< 663700:
return WalletBirthday(
height: 663150,
hash: "0000000002fd3be4c24c437bd22620901617125ec2a3a6c902ec9a6c06f734fc",
time: 1576821833,
tree: "01ec6278a1bed9e1b080fd60ef50eb17411645e3746ff129283712bc4757ecc833001001b4e1d4a26ac4a2810b57a14f4ffb69395f55dde5674ecd2462af96f9126e054701a36afb68534f640938bdffd80dfcb3f4d5e232488abbf67d049b33a761e7ed6901a16e35205fb7fe626a9b13fc43e1d2b98a9c241f99f93d5e93a735454073025401f5b9bcbf3d0e3c83f95ee79299e8aeadf30af07717bda15ffb7a3d00243b58570001fa6d4c2390e205f81d86b85ace0b48f3ce0afb78eeef3e14c70bcfd7c5f0191c0000011bc9521263584de20822f9483e7edb5af54150c4823c775b2efc6a1eded9625501a6030f8d4b588681eddb66cad63f09c5c7519db49500fc56ebd481ce5e903c22000163f4eec5a2fe00a5f45e71e1542ff01e937d2210c99f03addcce5314a5278b2d0163ab01f46a3bb6ea46f5a19d5bdd59eb3f81e19cfa6d10ab0fd5566c7a16992601fa6980c053d84f809b6abcf35690f03a11f87b28e3240828e32e3f57af41e54e01319312241b0031e3a255b0d708750b4cb3f3fe79e3503fe488cc8db1dd00753801754bb593ea42d231a7ddf367640f09bbf59dc00f2c1d2003cc340e0c016b5b13"
)
case 663700 ..< 670000:
return WalletBirthday(
height: 663700,
hash: "0000000000d387fab4c980e9a5b42ec35a39879706398c78fbce873d61f1b26c",
time: 1576863287,
tree: "014bd3b38c782ea2e66c053afd4c29c84fa27003b71de5f9778a631558ee7a1410001001534a90ede3e8dcb7115c84e86b2d184c0f46d5b21023a7292ecfade5e956e66500000001daeb30618bfdfa00999f2989795562775c3fdf95ce279d106c0e608fedc9ea31000001686ac0ccce56b47cab1dd4fceb48812f72d6ac6fff3a2ae5a9dcf27eda409a0b011bc9521263584de20822f9483e7edb5af54150c4823c775b2efc6a1eded9625501a6030f8d4b588681eddb66cad63f09c5c7519db49500fc56ebd481ce5e903c22000163f4eec5a2fe00a5f45e71e1542ff01e937d2210c99f03addcce5314a5278b2d0163ab01f46a3bb6ea46f5a19d5bdd59eb3f81e19cfa6d10ab0fd5566c7a16992601fa6980c053d84f809b6abcf35690f03a11f87b28e3240828e32e3f57af41e54e01319312241b0031e3a255b0d708750b4cb3f3fe79e3503fe488cc8db1dd00753801754bb593ea42d231a7ddf367640f09bbf59dc00f2c1d2003cc340e0c016b5b13"
)
case 670000 ..< 680000:
return WalletBirthday(
height: 670000,
hash: "000000000086313791aca867bf60fc7434fe2b3fc56926ef46223c6b6b05b5fd",
time: 1577338346,
tree: "01e38b18dcf2de5e9ca5c12a1329176b37219546cfabd9333a9536d2d3ef6cba3e01c159856a741f9da500a9c83935ee7323d63f589a117e66874612e70cdf7a9f4b1001db5e89b8cbf677a87375395940f4715de1bb951f05efbbc4fb34bb1990dd80600155dbaaf5b93f338d1c629fe2a77328c7609c59c6a767a6ccfcc14d3c8c7d826100000001d9e9451fe610b3374b30c711f62a29700ecd2b02e096f02085b896d3fdc3886401006895fa87a8083ae5d0d38df876e764486c67a684706f7750ee19c872dc5d2e01f5cc54720296c3379ac6fb0aa3ed6824bcc40894b3f40d9d2e2d1ed3e6080c3501e9fc6273cadcc40df45ee63984330cfe702a1e7b4c324516d1a80ebcacc4d4170125719ebec43e9148ecc5cfdb2359074badb6fc7759817f6afab999570a75a2000171b36f07e48c45e39f1cc02a99023236f1df60ae924b5ef14ddacc7885994e2b0163f4eec5a2fe00a5f45e71e1542ff01e937d2210c99f03addcce5314a5278b2d0163ab01f46a3bb6ea46f5a19d5bdd59eb3f81e19cfa6d10ab0fd5566c7a16992601fa6980c053d84f809b6abcf35690f03a11f87b28e3240828e32e3f57af41e54e01319312241b0031e3a255b0d708750b4cb3f3fe79e3503fe488cc8db1dd00753801754bb593ea42d231a7ddf367640f09bbf59dc00f2c1d2003cc340e0c016b5b13"
)
case 680000 ..< 690000:
return WalletBirthday(
height: 680000,
hash: "0000000001f2e08db1ea7ce567a5cd745de87c2eafbd769346b8212cc922d517",
time: 1578091375,
tree: "01bc7b45da508ff7e4b3dbc1184a42a646a18ad0c73907d9462199354f3490ec00001101cf1bc2f3ef2e491a4c04cede4efa561dcb4e9c56562adaa79b96ec8e54b43643000001419a6936943299e8d695fb98c78153499682d1c332efa1fbd19ce3c996be713b01e3743cb66129e262add8996fc588df0b1a33366df4e5d618ec14d0bc8129f537000000000141b1ff5b5fdad24aafa550d42cb9f99c85f6175b3d65060079bb9638cacf654e0141754203644e6f3d5faf15f16492efec723da55b2db473b34299c5582e883e46000000000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
)
case 690000 ..< 692345:
return WalletBirthday(
height: 690000,
hash: "0000000000b1e6422ecd9292951b36ebb94e8926bbd33df8445b574b4be14f79",
time: 1578845180,
tree: "0117ffc074ef0f54651b2bc78d594e5ff786d9828ae78b1db972cd479669e8dd2401cc1b37d13f3b7d1fa2ead08493d275bfca976dd482e8dd879bf62b987652f63811013d84614158c7810753cc663f7a3da757f84f77744a24490eb07ce07af1daa92e0000017472a22c4064648ff260cbec8d85c273c5cd190dab7800f4978d473322dab1200001c7a1fd3786de051015c90f39143f3cfb89f2ea8bb5155520547ecfbefcdc382a0000000001d0c515cd513b49e397bf96d895a941aed4869ff2ff925939a34572c078dc16470121c1efd29f85680334050ee2a7e0d09fde474f90e573d85b7c9d337a5465625a0000000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
)
case 692345 ..< 693400:
return WalletBirthday(
height: 692345,
hash: "0000000002584662ea3fb1969a65f05cf1e0c82581b885fbd723eed6ba818e99",
time: 1579021581,
tree: "01a30b15d800be77c5c959f57466a2c6dcf3e583010c1308a6956e23ec1b4658180140ead0f57ec26315bc14ac9a03ee843f34d080f41d2a682d824a02d73569446011000001d4d84c0e533c23813285e3849abff78ff36d2fc4b82c35061aed5e20a13c1859000191e51cd5f2f0afa0de7cd18fde39feb724bdc225fc25a9c75acbae1b641a7719016c33f322bc0205623943faa2a270b2925176cfc642da9625bd567e06b13c4d14000193726f6855f49bda4fb05a256bfcb17bf6ebac59b69ef9bfa73d69ac65ab2c2e01875259d77037ad0de128f071d2b85dfefd4d14c29e3fbd573abf843ebe5d830d0001d0c515cd513b49e397bf96d895a941aed4869ff2ff925939a34572c078dc16470121c1efd29f85680334050ee2a7e0d09fde474f90e573d85b7c9d337a5465625a0000000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
)
case 693400 ..< 700000:
return WalletBirthday(
height: 693400,
hash: "0000000001708386101e361d211b2a14f3571d0b81f5962b452d563444c7f06a",
time: 1579101218,
tree: "0110939e236e3f13fbf9a044dc4e8d0094b777ee950dca49cb0722556b08fbef2f0197c4a6daa51f5c699ba5f0c3e53b657e54e3d728e60edaf76b4e2215d6aa2d661100000001ef66b21ca159b57a3d54147b0011c096d20cb3aa9590becf8f026c9edadba61a01750454b0edee9cc2f1eaf6d34cb8e495679048008d8cf6c1ab4321bddb828a2901f3dab23e140f2c400b4d4b5e6003ba2c7b316721b0d2858c8e0fcd1f5acbfd4b01eb786638efecd4413cfaadc48a0275035b2d484b92e305cb086c581a07390d21000001a4711f58e3fa6f5d38e2f54ab424c3014c119629fab5ee8a4ed2814d7b17036d01d0c515cd513b49e397bf96d895a941aed4869ff2ff925939a34572c078dc16470121c1efd29f85680334050ee2a7e0d09fde474f90e573d85b7c9d337a5465625a0000000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
)
case 700000 ..< 710000:
return WalletBirthday(
height: 700000,
hash: "0000000000c057d167a20ae61b1f77996bc72631dee6ffb11095f0d312230ddc",
time: 1579598443,
tree: "01c6b273aee226912526622b91e48a0ff5caf71f1f47569aff8a1c145102b02328012758ab750e1cb4f933ebca089d23ead6032151a38266aa020ae84557bb61844811016443e86acd06140aa932467bcc7235704cf95081e2e5faaf031112a9abd5f930016d1847eb52f8218773e3d2dd8eb19950dbe693484098d763010d7c338337cf68018117bb5e4ad68438572aaa55cb7d66b4b86b9d8310fbb4e36db7982dcc28591400012c4e84168b1c9a322f6035ddb5989fea843045d22182ee9ce45a6a8f6831954301abf6a411ff1708af6252bf921625f28931c567d92833d7ed2b2b14efd6b06e5001d1f934bce5476ef5d21b384c7dddfcbd8c1f630435acbf26a094bc46757f5d3501e6a69ddf114c92d39370a24e840c46ed42fc54a63986d3aa916a08c2a922c73b0001a626bb2ed07614f7228f79d5fbccf541699895842341602c639ab7516b1c9a1a0000019be74b905f0e99399af0fda6832324ceeeaf57551b11b42c73bcb7cd215ab91400000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
)
case 710000 ..< 720000:
return WalletBirthday(
height: 710000,
hash: "00000000003adcad055353d33a0962103e284bc47577c62580535a1dd6be7cf6",
time: 1580351806,
tree: "01bf61bd9326bba72206cc0ac82791fe316277907ba76773b5ae01ea7df948ae04001101200905d2485346e39f07fd989ba05211195251968d6bcb41b8280bc94733bc5d01e44932d89c5309ac906072235443f573a92dcda2acf608c1851af01dbeab19350000000001a73367559bf511fc5212ab3f0f6754a9b7ca59a3da68588e3763c801c031bd1501eb94b48e208bdbd42bb4815940b2f9f5187cc5e42c196f461f7bc6d020ed670f0001f00ddf03aca4e8c2620ff274939a1f1cd6a4eceb147e8aa6a8ba83717d60182700010576ef08575c3dd49296ba7c2ddd914715c4f9a7316da4ae8f5600dafa1b1c39019be74b905f0e99399af0fda6832324ceeeaf57551b11b42c73bcb7cd215ab91400000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
)
case 720000 ..< 730000:
return WalletBirthday(
height: 720000,
hash: "000000000225bab0e1491d6abfa4a41c174bc7d0167411e2cb2ebd960dae5158",
time: 1581104786,
tree: "0147c6af2c835328a4c17eff07f76102dc57716a13ce3d3a4f48367c3f2384fe2901e01e9b45be2ad8bedab63db1963c2b8d85e1ed20b6327cf2c55c211234e8a3351101134f80e61b548e384e87f823187d2734b07c516d48eea33a533c6cf7aa47052200000000000000017ce48111238d9e81b7e4147286578f2d686d71b1ec0cae668f567f3fef65bc0b017895f4c380f5169dcb84c7154fe6fcf72d694d30f0ba2535437b443a2cb5ae18000000013a1f7fb005388ac6f04099b647ed85d8b025d8ae4b178c2376b473b121b8c052000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
)
case 730000 ..< 735000:
return WalletBirthday(
height: 730000,
hash: "0000000002293b9e058e17fbc357c9b676d276eba338e033e357034c775ab320",
time: 1581858634,
tree: "019a59eba6efd060a61cde70daa7b34202e5fd55fcbf809eaf0aa3252e45810e48001101e106c6f8a17723af8793c1bd0f0e95dbcf5ef0bd80e20195422d8388db48cf24000001907e2c08367bfb45d196771ad267ec773c80ff4306aa7c4d2415ee22d211e90a00000001d72bda7061e4086bb885d6f26e39aa603a1f6db2e4fc71ae65a571c7a31ade27014df2a298ce5d7f8e88617b66ef7dc1fddd854e8dc623c3dc0faaa0eb93137d45017a48dab02dd9a014df0bd310657c3b8e854e24e1137f2ffcb1db693e38a4416d00011a5c078f7dd38704665b7270ebd90366fdd0edccdf284ca1f03c6d7e0536182800013a1f7fb005388ac6f04099b647ed85d8b025d8ae4b178c2376b473b121b8c052000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
)
case 735000 ..< 750000:
return WalletBirthday(
height: 735000,
hash: "00000000015c597fab53f58b9e1ededbe8bd83ca0203788e2039eceeb0d65ca6",
time: 1582235356,
tree: "0161f2ff97ff6ac6a90f9bce76c11710460f4944d8695aecc7dc99e34cad0131040011015325b185e23e82562db27817be996ffade9597181244f67efc40561aeb9dde1101daeffadc9e38f755bcb55a847a1278518a0ba4a2ef33b2fe01bbb3eb242ab0070000000000011c51f9077e3f7e28e8e337eaf4bb99b41acbc853a37dcc1e172467a1c919fe4100010bb1f55481b2268ef31997dc0fb6b48a530bc17870220f156d832326c433eb0a010b3768d3bf7868a67823e022f49be67982d0588e7041c498a756024750065a4a0001a9e1bf4bccb48b14b544e770f21d48f2d3ad8d6ca54eccc92f60634e3078eb48013a1f7fb005388ac6f04099b647ed85d8b025d8ae4b178c2376b473b121b8c052000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
)
case 750000 ..< 775000:
return WalletBirthday(
height: 750000,
hash: "00000000028522f87172ecefd79b5f54547c8a756976585f29e4dc182a19c46a",
time: 1583365678,
tree: "01a069618d376feebdbf39030c254a1a3cb46d19369837e44b6ad9afb43763167300110000010c256f47b493d8d94dd5ad09a6829a0a5e346400430b222072583afad8ce847101b261be33d5db156d09fa73031e8f37b4fe4193d21c909e2c8e58d86c7e48690a016b4a7608e90189275f7bb8e70f525c333431ceaa8de9d5b119e66ce2faeb79290000017d730339d1d4bf490eda3c1fca77d7b8a769fff083318ec46a81404fef45f046013ad81619e96171627f27cd6e7755c4d8261dc7017a65753f06c6cf9a29af116201474991dfe7d598257dae28820c6058e389a897e232e737c90a5427e8f24e355e0163734115d47b641de26abf2cad5c4ac1cb438869fc91d50e66444980647aed24000000017d066851cc49b2ea0cf9fb6af00adbb1cc3a0b15cb02d39e0a66f031b2dc1f230001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
)
case 775000 ..< 800000:
return WalletBirthday(
height: 775000,
hash: "0000000001325ee365bb14184794c700485f4e40142678bba749a54ccbc91aaf",
time: 1585250621,
tree: "014f09c863f64727b7cada08271c34d1ea0ba728ad53ec979c25bcab5a902afd52001100000001a182b7bb8fd9e872892c872fc813b59bafc3b517e55a714ff7c4ae45870a1a4a00018133f585dd7c438f78ee970e97036a471897cd5cb8df897ca46b7f2ae6567b00019338310381f33bfdcfe40b56ca7aff105872e6284d2953c287891201e75a237201e99c0f7b97c5856efabcd2fb46ab456cf5d811c3c39aabbdbb40daa814bcad6701e97f12a640f75d28510cbb7d4cad99d46903017fa9caab9905c108ed13e3c62e00000001e07372caea187301a24f9dbbe3b6a8981bb4225b7f4b362b01000d4b0a0eb071011545fef7ddad5a52664dff5a73fbbb26c2cdf42aec9292349773079432d5bc46017d066851cc49b2ea0cf9fb6af00adbb1cc3a0b15cb02d39e0a66f031b2dc1f230001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
)
case 800000 ..< 820000:
return WalletBirthday(
height: 800000,
hash: "00000000013f1f4e5634e896ebdbe63dec115547c1480de0d83c64426f913c27",
time: 1587134100,
tree: "01a8689663d3c4ff2bb9aaeb7b75e66a7c68705d147bea9fe67cf7f1ffa9a071720011000196bff8c908d7015ad5df6bc5f5268a157da076c5d2ba63d222f0353c8810320100000001b0a0c048035d6f3f229bedadb2fb7688d03bc49062eae092666a8a55883afb0d000000013a365306be60039724201a594b84cb24ae09ea92a3077722da662289471f6658000184abf3f567f42573deb9e2ae56557fb6a763f16f90577ba5511b55c090eb6f2e00014da3714363acb83872f51c87fed3d42a1093420c3cb96b74ad65966ce27e8c4e0001e2bf698f5ac10b44da560d11a5e1d5c191a82a968a2be0a6948aa8748b54516001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
)
case 820000 ..< 830000:
return WalletBirthday(
height: 820000,
hash: "00000000001bde1cd7d26b21c7c0a4eccf3c16805c6e68f499398463fa91ed93",
time: 1588640783,
tree: "0127679ec6e5f7205bd7088782922da4afd0606bf5404faf74feeebe5f548d3639018f80d63358b79bdbdd5a19c6fe3c76e8542f6a1a309ed1dedad95fe3ca5016681101f1a4674cf60a7a56e52fde0a308481a4c9b77f059687b965dffcd67be7c4a83101ed990844ef4a7751262755367e6e16d5e351f190fca5f07124a8f71efee2cc1900000001e83b41c625d651681527f2a95ff2925b96f77c1311144e191da1a59303e39a4200000001f33bcadb822e6d55ba2fa044e2c790d957bc8dd7a6ea773d92114517a97ea76501e0b92e780e46114e308d615f417d051613215bc5974946a4b056013d6351f52401ae652143148288b1328e1b511803db03fbdf319ee20da5c7e49374331c525d3a0000011e76743978cad6dd5263d5a654db307368cb997b0c984ad51018d007c955972101e2bf698f5ac10b44da560d11a5e1d5c191a82a968a2be0a6948aa8748b54516001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
)
case 830000 ..< 840000:
return WalletBirthday(
height: 830000,
hash: "00000000013284f6e727ed7cb6365726a044e050d0009ca4bcfbc7bdcd80f319",
time: 1589394076,
tree: "01a6bcb9b2f15aaa3e69ca0c0688c18b8859d54c9d6388f4d5fce8f72a2bfd990d0011019bcf88f0f1cf6d4cee6b74231c9466cd13b5e5390d4e05fdb1e4f4143cdf7a4f000000000145e054aa42c1c6f9a70581e04b05a565c9e6e2faf8885e9b76afcd841228715d01a20db43a61e0bc593598bc42c7b10c31194385c8fb00543cab4d4756b3eaf9030000014bb574ca908dc46d48278d9f5039b7d93217ea00eb63f682321503fe5b42b03f0001d6bdb5e3f2e34961d6f337c416704b74d0df45349b7b50e30cfaebea4934db1b0001e3586da44e3b0d6a0776f967e86c9bb7542b070ce52a7baac5a8e2a564780743011e76743978cad6dd5263d5a654db307368cb997b0c984ad51018d007c955972101e2bf698f5ac10b44da560d11a5e1d5c191a82a968a2be0a6948aa8748b54516001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
)
case 840000 ..< 850000:
return WalletBirthday(
height: 840000,
hash: "00000000000a0b9a8753dfd46e1205590d35f4d365437a0d20d29317b33743c0",
time: 1590149064,
tree: "01101f7b8112735869abc0e74dac1f272935d09725ff03cd8cb63d472e112fa82a01d635e219273ade2859554e5191898ce9a79cb80f62c272dede1c2a71e183e21e120000000000000000000000000000000000011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 850000 ..< 861500:
return WalletBirthday(
height: 850000,
hash: "00000000007b5c713129e71fc1496bcc321cd6cd3efec262c9fd73eb90695faa",
time: 1590901979,
tree: "015063008b28e034d7515616a1d975646927df30ac4f13d96ecf3f7ec1ddd49b26001201ff3ab46b9dedd6374a80ddcc746a63b05f9dacd6dbd21f7e0df00ec6df0156520157bfc70827a774ac00c13012ac96a984d75c54a15605d741f647923d531021420000014d624d2cd2908d1a438f4a70ac392ba151c7167095553556f23ca5612475224001b97205b2715b57b9f04451df4474c73586e8fc438f989b057cb83c24e7c80d5d0001d0ce3df812f137bfb07e56795014bfc66297491dde457df799406286d7287e1c0001a8e22e1a09d435fcf20b2599688e7094ca46d2c273ffcdfee0ee80eb3e1e4d2901e469171a108b4c837f17a8f67f4d02ff9688acc825d2e1ce1ad3f8b24ff1346c0001a8ee7010fb0075cf00f14f7541c57cd0e18167ac8b98c1b20454d3618715811a00000000011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 861500 ..< 875000:
return WalletBirthday(
height: 861500,
hash: "0000000000f1525a1691846ed82b5bde1d68f5472a88cdb46e2614a0471c2bb1",
time: 1591768624,
tree: "014c3e4b358ad1a1095473984cb037f6b3a326e7c4d6243371b96d774be49d3b6c012f872ee6f08d4348ac8784a055ceca2003b5652956970110ab8ac34662056a6812000184579254ecf2242817a5372a6c93e695d520ba6994a1549722ef6a1e06c4c241018cbbc978565f1f0505facf3761bd072a9bcf0734c49dff1f0f8a40ac0b02ae0301cdac68e2a12c011704388b381617237292c4a219b56b358999f3cf2196fff53d00000001c2fd85c8cb0e8ff63eaa7722a58aa6fbc6298afaca10e3bd3131e6cdf4f3fd1101931ad087d1cd97f85debd36de84dd1f8b3147d82e7c21bf8f68d9b444fe2c86d0001e99fdf5156ce831cafc19295c3239f54727ee3c8e6a9383da5e99f0d37384c690125cc58b7c9dcf14d773e7291fd53fb94371be34ada296701fcda2d1fa903da1f000129505087ffb37278c6371e20c51c2c5dfecc8317f6b0a676137f84467c4ba621000000011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 875000 ..< 900000:
return WalletBirthday(
height: 875000,
hash: "000000000001f4b0caae8da2eed537aedd4a76d8671fa668bad870995861296a",
time: 1592786164,
tree: "019e1115ee6526f412ae2f8185b6f1e41e1288daf1c6e4629c32a12e1880211f64001201fd273a938cd5f5fcf70a758fab2d852efd000db4b6b7a8da860e8e48a5fe7614000000000001ff7f557fdde5c41e043e2fa0160e3b8a7fc0331462d1cec6fff3db133e3dc64c01a71c9ce180b19137b80b28137bb5a393bbc26b4b807faf4d57984d1f98b7fa45017d8e8e44760406694aab9880152fcf2d71a0d3967fbf001b77cd9751d61e1924019cc66c08d0b19b5fd3d69f32be1e76096ceeb1b830532eea9ec8aeea5d91076b0001c93ef42efb351f52c49ee3280457d8de5a657015eb9e5a28c6b63c020c18de13000001166bb2e71749ab956e549119ce9099df3dbb053409ff89d0d86a17d5b02d015d0000011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 900000 ..< 930000:
return WalletBirthday(
height: 900000,
hash: "0000000000d99076161c66dd3e86db9f9390921cc8b0ad7d6eface3a5d8ecb1c",
time: 1594669980,
tree: "0162267b975eb64d5e602e9bfa63c56b1326e8eab6fa971847f2d4f8f27d26f90101cc33a70cde4e4e5f5347034f44b503e8660c7380e596961ccab15d7a64044371120140d08a6c2958e7283c3e95053eeb3e5cf502d5857a961e107c8b37ae00dcb30700019f7e8cf60fb1b31d852d6786fe74078ff1cae30fd982ed2ee11176f96103622301d3f9f17d782359f08d500309ded4ddc1488c86906f3bd742aa95b8de0f189524000001b64361426e35478691ef23c34cf977afab4962c0d7d1998b08ccac635149524201a73426649efdd3a6bda5f8a253a4823f8558dc16d8042ba071f13c0575a3955d0181e81df06e97ade7989e0ce8790f75f1d34e6cfeb4347205c4aaa7adf90a180e0001ecd87912a28cfbe4f34bf57bad9827e4013d8d4c8e85c48bfdd06c35eade9920010d393867f4f2bebf9f603bf827dd015aaf3a46dfa8b68d86cdce07aa4fbb97240001d3ddf137881180d7c5fd73d188c4346291168bde688643855eb3cd5f680f9c0001166bb2e71749ab956e549119ce9099df3dbb053409ff89d0d86a17d5b02d015d0000011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 930000 ..< 940000:
return WalletBirthday(
height: 930000,
hash: "0000000000a5b606b5e99c3f155158993395d4b624e0ead68bdb3130fea8c720",
time: 1596931609,
tree: "012ee9cbe55d438e5fdf9fa2df34a989514d038fc50d5913303221392dc3b33257014c2cabd5f58b23406cbcde4034d5b62c3023f30ea9a0ea5ffafb66fb7e4f000e120116683075450cb081d897a78d86224019865ce7e3ead189e74286be307f43ac5c00000001b9da9a7344e04ad7be9cfbc57c89e840703264f5692060a5ea4f7c2e201f5e42000001a3db46e41c1c7e1026ee8b49b9a148f53b00a9c728f72b996c2dc8fafbe4cb2c0001bc597d37e5f726d22ddbe544885571ac89f5fc1746c3e7e198d0bbe85b77196a011439e56aa582ec419f2a0004222be95ea1762876ea33912c5830ab4e8bdc02660163a8ebc9ee4b289becb230ef62829a8c8b4820fcd11409f0b4c849190155a65f00000001f1c57245fff8dbc2d3efe5a0953eafdedeb06e18a3ad4f1e4042ee76623f803200011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 940000 ..< 950000:
return WalletBirthday(
height: 940000,
hash: "00000000004f3d5203454e18248bc021a2afa1a30b6517f34cd9187f2b8e2489",
time: 1597685856,
tree: "01dd59466cdc00ee8ceb305d15c25ef32aa2d96b7e4536e071c1d14e67aee9ee0b001200000001defc97883745ef01fbca65d4e5c0f8e22b7714b704a1c36fe8a851fdbfe3a1160178cf44f19dda025a44490dd37b96b83758d04cfa3b26476e129173e7c70cb103000167b3485f4aefed9426fc301de1138fedf6949fc806c54acc2b86d897cb6a2041000000000103e2fcbb87cd5fb954d55d094943fbac487ecda1384a8fa7dbf61097a9755e54014104c9c36ff1a2e7eda524840463de4e2c02f10412a33dd754564d76f458c525000001f1c57245fff8dbc2d3efe5a0953eafdedeb06e18a3ad4f1e4042ee76623f803200011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 940000 ..< 950000:
return WalletBirthday(
height: 950000,
hash: "00000000016bed6cb8b8c2c09791cee821093484fd9ba0f3faad1e78e0d21c17",
time: 1598439138,
tree: "018b0ff026a6c3d70e5592d7b42fa829ec41c5a86faa2d12cbbcdf81e039cbee5301f4decddef8e3183dac4de8d1b9aa3918d7df9293aae3c1931f99a253149fb65312019066138ebf0e6cfefbe9cd7876aada7d3f27834d604f827b56b7a56e1a7b551d0000018d080dcdf356c41f5a86d2062ca9e617965faae9b9a7ea678d3799f526a353130001a5ba52f3a03ce38d7d48afc3d2c9e6d65e90dba09b53ad3d3a5921267375de5d016b84dd3e9242073d7069f797bc81a4ccbe0d3847a3b3b4d1376d9e6d61446605015d52a3c83f77ec5c8e823143e74569c0040e1cb58d2a170ce907ae010ba29c670001be5b81f3b1b8a035bd0894392b0b78bdae4c57f206d3875b933de545f65bd93b000000018e1d474609c9c09894638a0ab3e656aadccaf7ddf12bcc6b6ece44a4cc79e1140001f1c57245fff8dbc2d3efe5a0953eafdedeb06e18a3ad4f1e4042ee76623f803200011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 951700 ..< 960000:
return WalletBirthday(
height: 951700,
hash: "0000000000e304a23ddbddd62d5fcd7e6b236afe22e529f1ba88f4dfffce432f",
time: 1598567019,
tree: "0154365cc76299ab7ddc51a9fe6fd63babdcbcafbe6d7b293c43493e4ee4dcaa2501fcbde4337c2a268da9e63035ea372706af6c3be6a7dca7ddb39e9f2293835f381201e7134cc658434206a1fc059bec482c4ea3abdb49f51f367dcfc6c854deb573410001e6dfa615206e90b438eedc5cb42ab5b8a1444ed442581f45813fd1a810cf246e000001f8a3271cd56cf8cb3b01b446cfd1e7afeab070a1d7a356da16858ff2d1636b4d01de38353596f623ce0028520063828e4720bfb4ecfcc3fc103d78fc0cbe7af64200000001064fdef5644d3f4f27cd28df0d3b8103c4822871e2883bc09dcf419f1444c85a0000018e1d474609c9c09894638a0ab3e656aadccaf7ddf12bcc6b6ece44a4cc79e1140001f1c57245fff8dbc2d3efe5a0953eafdedeb06e18a3ad4f1e4042ee76623f803200011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 960000 ..< 970000:
return WalletBirthday(
height: 960000,
hash: "0000000000b5b5e0ba1c01f76b8105878ea3c2f11da53cb0ec684f5d94365421",
time: 1599193083,
tree: "014695c74583a750216dbc0aec38282d86fc17b595bb45a74bbee8fdbf46b5313e01c2253474715b00c618e635815bd16fb8e6368fdaa9bf8f4a1aca34ead6a7eb1c12000000010cf46f452fc9101af9ca34ae364a1c2e20bc05d454068cf1407a2ee3e0c9ca6700000001091c0b4153defbfad723bf14e1ccd07c0258ea1fcd6e9e8cf759834112ec3036000001c2c980c0777874ce748ca549838324eb775cb2ac7a8d42793edbb05ac15c5b4201162d1417d8b9659ec93ac26ba1a888719a43ab1fe0b46a33c05c2aa55fecb41b00018e1d474609c9c09894638a0ab3e656aadccaf7ddf12bcc6b6ece44a4cc79e1140001f1c57245fff8dbc2d3efe5a0953eafdedeb06e18a3ad4f1e4042ee76623f803200011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 970000 ..< 980000:
return WalletBirthday(
height: 970000,
hash: "0000000001dca1d101526285476ddf0eef6d238d5b01b7fae8062edfc09812c3",
time: 1599946198,
tree: "01d9e6147caab719ae68cb20d976c78437634e2c999ef3a09c6ba35086d443703d00120001019d135be7b1db088c68bd76703ec2b45066bb1761619745362e61dcf55f644601d0c8f296479a73722c2e2a260ab7017b9a9e6d084b651289cfe6d3c7a00ff54e01f853ab39dbfc81e2aabefd231d3374ff794028168c725ad465e61205692fef4b014f13b6e4475cbd004b4d95aa8205ed7338224e13627ecbb19afd1937dcbc0818000185b4f1ddee3199cd1f7913b223c01c4623cd9d0e1b47df4e36aaca7717b6331f011d6c8ec914cc312ef0962d52240308b22a647f4cbd2d7c2fd420ad5fbcae5619011e43cbb05b8efc885531367e5f611fe7ce7514131be892cce3adad02e151f72b01f0d7e0d589c7e5f8fff0bdd5037aeb5d5d818d413262758c9915ded705e40f70000101d26ff60e77e23fb86a52da565c22d76f81df7f25d543ec0e58a0d692d4be2700000110b2bfd32a99e0b982a41a6dbaebf783bdb9d6af795f5f20056ce7317d15ce1101f1c57245fff8dbc2d3efe5a0953eafdedeb06e18a3ad4f1e4042ee76623f803200011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 980000 ..< 998500:
return WalletBirthday(
height: 980000,
hash: "00000000005de60d31b653cdf1637f1bad62af844c6c51f38557a4e8bb74e2d7",
time: 1600700163,
tree: "0184330bda72e9596256847a9597d7d9476aa3d69d9dad2149314751e708da206601cd8a1a61df1e80514cd2c0a7faac8b8d7ce27d6d96bb63cb7c61c1f33e7c654312014098788b75f26108d93f0429202ffffb6cf9ffffd7278383e4d8ad2af642264600011c035ed934a11c1b48e24b6be9b2d483e7747dd082f06abf75f9a092b34cd33c01be00394a99bd33304fc4343cd928857ae7c09c176452f40d9815f9ff3ba3865d013bd7218072e1588aea0568198d37e0d83ba75f155c863355974c4eb864de0103019ed27335bc5452e320ec22a30cfe61508929016157ff2a555181a9a0623e725801328208bea2c5c83487effab780cdb36b4b82e6e7290b06d98817a160f3d79d2800019ed6779a1724a107807baf4dda9481fb940f50d85db701dda43a0989c2d62535000001d1e806194dbe171d4ad1ef8c73c1a469130caced0e24b04b8acef91c42be7a56000107771e04f7d6371bfda40ef9e04419a25c6563dcd359c85bd501de28c3c7f3250110b2bfd32a99e0b982a41a6dbaebf783bdb9d6af795f5f20056ce7317d15ce1101f1c57245fff8dbc2d3efe5a0953eafdedeb06e18a3ad4f1e4042ee76623f803200011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 998500 ..< 1000000:
return WalletBirthday(
height: 998500,
hash: "00000000014cf0915c4f105140e846c62ca6f2e321f4f717cf6762a35c6e8eb4",
time: 1602093677,
tree: "01b86ad8964b68a9a316a3038af14ac9e557a6eed614ee5d337c9fdb8887e9dc6001b71fbc815cc014a7f68648fcad5b9b72920b3d21cce406b5f593a0eab6d91f1212000001aede58c0641825b7531a8b296b9fdc7393090b87588893e8dd5160bd59b2e16300000000014fa30e43b641cf67c84cef81083b81bec3bd677f55def5c7bd948298e64690560134ac55ded091faef2ae8a1043704dfec41b1a95c4cedf1818574752bc40f2033000103ee02ae59c6688dcaadf1c4ff95e7b1a902837e4989a4c4994dce7dac6ecb20014ff8c0fe6bce02ac4ad684996bfa931d61c724015d797642819361d611ebd61201c7ae83949d9502b0eff10618124d335f046e4aae52c19ccad5567feceb342a5200000001b7fc5791e3650729b7e1e38ee8c4ea9da612a07b4bf412cefaffbab7ac74c547011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 1000000 ..< 1010000:
return WalletBirthday(
height: 1000000,
hash: "000000000062eff9ae053020017bfef24e521a2704c5ec9ead2a4608ac70fc7a",
time: 1602206541,
tree: "01a4d1f92e2c051e039ca80b14a86d35c755d88ff9856a3c562da4ed14f77f5d0e0012000001f1ff712c8269b7eb11df56b23f8263d59bc4bb2bbc449973e1c85f399c433a0401e0e8b56e5d56de16c173d83c2d96d4e2f94ce0cbd323a53434c647deff020c08000129acf59ead19b76e487e47cf1d100e953acedc62afa6b384f91a620321b1585300018179961f79f609e6759032f3466067548244c3fe0bf31d275d1b6595bb2d486401b622d3f80d8231c44483faa2a27e96e06a2e08d099b26d15828e8f0bde0bd42001a8d1f585aeceb5c3f22ffb43014fe89db9f7efc080361d4fa4e8d596ab1224400103ee02ae59c6688dcaadf1c4ff95e7b1a902837e4989a4c4994dce7dac6ecb20014ff8c0fe6bce02ac4ad684996bfa931d61c724015d797642819361d611ebd61201c7ae83949d9502b0eff10618124d335f046e4aae52c19ccad5567feceb342a5200000001b7fc5791e3650729b7e1e38ee8c4ea9da612a07b4bf412cefaffbab7ac74c547011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 1010000 ..< 1020000:
return WalletBirthday(
height: 1010000,
hash: "0000000000faa7ec382bf9c0c1abae839f663834f8f307a2141b1403bc85fcbb",
time: 1602960322,
tree: "01f89aad9f6ed7532fc8866580ad425ba2a63ade58b064be8448804ccf9a60fd68001201dd7166b177a37db095801301de34572e69cf151db80201ee08d677c8a1a7986f000001d30d2ef05fd6f29519da13f09623f440c0f8dcc8154c56dc7f881c77c3504f2201b3ae640c5770b95f68aa24c57c32c01713e450c63b1bc5535ebc81ef2a26b519018611a216a563b1cf44cb1b27821c076869676b7b341a5b4f2cef10e8896a364101091d319cbcb2ed9b4caef347a32268ca70012899b85cf438ecf4bd6d6700c04e01337e6de0bdb259c3bd864fec2617a2cd9e127a7e6ba4212a1a7b9ae8c65e2d1c01121f952ffbab89fac050c927d06f855f8baa39ceb1584a5144c32b45d6bbe35a0110188995758e67a4c8a9e71aaecc9a7bc94e085d189252b385eab74587424e5c0000011ed4073019f93951e17d7e19f48d922bb6f3a9aa1a4827e619e0ae791c9539240128e88325aeb1eaae03e9085f4128fb62f367aaf4a6340dadffe427c1d66aa445000001b7fc5791e3650729b7e1e38ee8c4ea9da612a07b4bf412cefaffbab7ac74c547011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 1020000 ..< 1030000:
return WalletBirthday(
height: 1020000,
hash: "0000000000c3c4887bd6f5d3cbf9030914e6d1bdd51370ade6657e831d9e3377",
time: 1603714448,
tree: "014f6722b03c84e99cb0f198c604fec8c1c395fa726f403e239a66b124d4ee2f7200120001d6920ed4fa9340ece9cc4918f8b5aba3b0ebc5be16831e7d56e6acc93a7e73110001c6cc38510b51ef7ef6dfd1d48df4ef97de8a52f19a9964ecb53301de1057760d018c66fe955d1c4a7dbeae31896dda4cc0bc7824abdea432101fed279a628f5a4f000001935ddd089f29e35bd356a176191995f91239127eb93bff018a3447f80615a05100000182e624e6852072075532264ac2cc76bcc92327ce55e1dd464817d4c6b9637a6e018d5dcc90c3e7134891d77aee71063b8d542b337e4d43f55f0db9cef746f5a732000001bde7578541c07920c1bc94312596adfcee32519cb80a95bcd06a1272c127ff020001b7fc5791e3650729b7e1e38ee8c4ea9da612a07b4bf412cefaffbab7ac74c547011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 1030000 ..< 1040000:
return WalletBirthday(
height: 1030000,
hash: "000000000216b8552281f6b73332ec873e0eb062f9b83ede4f3102af78446b7c",
time: 1604467637,
tree: "016f037481382b438c1a41d74153ee8a6131db5a9fcfa2526718e7b4fa1577e658001201622ea365daf3d6cbd5b712bb33b77764708d69f852b903f053c47569cabd930a0001e2175829e38f95f1b3415bdaa796a732d83da1b137e1b0aecfa9802b8c8e9a540001c783c98897bc46693d1d2d2891489663f0d9ff12b34f28b3db5a841236d9d76501d671aaba2921e416e7b7b81a89cb8e524cb6c49d89c575e04e0da0461799216f0001ba538b78350bfeae6538bfac75fe8709eb59bb72f6d74d64c92df41ac1e464560001ef2204037f952a1365afd291acf2361dcebda719b5e659de073ebe2f7f3eae1a01264c173c66e9b7c36ac9f7a6c928600107fa40f11b8d81862464f849885c50620189c3e3ed72b0d445f043e2d2d5ec23c693ef67b9a15488911ad35480a6041c6301f7f497a2f9ded8bb6d14d9f1bb83f43396270e1fc7e86c2c789d9b74b9d2d3070001bde7578541c07920c1bc94312596adfcee32519cb80a95bcd06a1272c127ff020001b7fc5791e3650729b7e1e38ee8c4ea9da612a07b4bf412cefaffbab7ac74c547011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 1040000 ..< 1050000:
return WalletBirthday(
height: 1040000,
hash: "0000000000852680280d876e4870ca18242527eb247994047dfd4b2601fb1fd1",
time: 1605220381,
tree: "01d4ad84ae2c7072a2632e767ef7d38d6adb125d76b2780d0dc32eb607bf839b3a0012000001677d02da42c17e72416ef72a07d165a142d3ab2d1363b07219c44b220bc58843000001035218b5415347549dd0315585ee95b8b1f811d81aca93a551478e3b04d0a527015df8455e3415c857ca94d357d48e093391715644afcfec96656b0b33bbc8592e0001d722471e81e674f55400ad26e5730a88e4a63138cc741c0aa40961ec9ce8076e000001c4d6088cf30ed54a892b82679f9531247c8dcefd1501d47f45bc35095af2e7070001347a0b5c418e301923ccc684d984b80b8ac1f52888b6d6021f7fe3676eafda1201bde7578541c07920c1bc94312596adfcee32519cb80a95bcd06a1272c127ff020001b7fc5791e3650729b7e1e38ee8c4ea9da612a07b4bf412cefaffbab7ac74c547011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 1050000 ..< 1060000:
return WalletBirthday(
height: 1050000,
hash: "000000000174c1aa6e70950d51e574311da9fe75b0ba66c38785c8934a00ad3d",
time: 1605974807,
tree: "019c0533c31d2d90c2ac6d8c9193bc9d57cb77ac24993a93202dd97ee8586dac72017ba6e3eae1efa5fec05a764fac9bd552caeba096e73840c4d6d71a46f3ca0f6b12016388275ca6bed5564c68f57c17aaa50e209a900b8f257b60c7e548d39946dc160000014d6580e971d6502e2ef9278cd5527f07c96ce26548d8e13e290708e517e6a40c0000000150d24a2ea34b9eeac3f79051e6ee9dbb8c482083a57ef1b1ccf5a1f164a00547000191cbb6ea3483a6a60f6598710cb210392b7469be8f650c7ea4491965e51fa51b01f0aa6de369775a9747bf7d5f034ee6a7604437f497ca45df942a45c53a99e93e0001e2aeb2d8da652922c8714924c41335140a40bd1c966dc611a9d88058839a881901347a0b5c418e301923ccc684d984b80b8ac1f52888b6d6021f7fe3676eafda1201bde7578541c07920c1bc94312596adfcee32519cb80a95bcd06a1272c127ff020001b7fc5791e3650729b7e1e38ee8c4ea9da612a07b4bf412cefaffbab7ac74c547011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 1060000 ..< 1070000:
return WalletBirthday(
height: 1060000,
hash: "0000000002a74e26908b2caab798d341430d83a012aefb113d9707acd6eb5162",
time: 1606729750,
tree: "014dccd8971611a03b3698c14e48f76d2526109374c0336a4aa0c0559567fafe0a01f0875252b1ec66c1835e362c19ec570b02b47c5a284477adc599f4868535370812018c94b59acb73c782a3b3b2d9c46babb6f6ef03e413b5816794518b839bb8d360011061c3e44c652e1ba70b85886fada65fc781b202335715489e21ebd64de8d92e01af2d971d01ebf43d4f1b99f500fe0a97e2068bf1ee03ac6e309316e7be88f221000143b8807fdc7a87ce8623370eeef95140aaf315c9e9df7bbf64a4faf34f4ba213000000011fe71b62cc883a426b1b623e3df4c91cae8de566fdc9a746253d6350bc48451c0001e15174bb37ccc2ad5cba5f9f879d459bec83e975afe6304d23980c0ab87fa34a0000000001891b1e6bfec42e97c79ec505c7ae1b584cf47d4ed8f6cdfcad815b02a5496f6701b7fc5791e3650729b7e1e38ee8c4ea9da612a07b4bf412cefaffbab7ac74c547011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 1070000 ..< 1080000:
return WalletBirthday(
height: 1080000,
hash: "0000000001a6faf5681b8565d50145fd84547b534c5f869e77cb802518d14341",
time: 1608237278,
tree: "01f3955ce270f5718bf68883ed37b3b9d2de8fd77be7bd95334fbedc6083f16026001200000001bd5dd7584bc157cebc9d63c7ee761ab453892482246aae3ef9db17de80b84a4b000195fa995a764f9afbd6c14984dbc72175f49f2259bcf0abc4a82ac92446532c44000168fb4180546c77370ff4175d40a29c357e5787f820e383028243ba623fce4e61017cd28108a3c64a8923444af9b7409eb5dda47d8536cf5aafc80abf62e9551b3501fc0832fb90a473de0da1ae7f62b03d547655aa82d1f279c5ab5a997d6472085901647f2444d093ad8668eac738fe0ff6b59b8191bcbc13dc53f581e64de755122a000101e8d7f1b32b8bc1ec539b93f6c2912c839a55c36c509711340a5cf6d1803a360103bcde16c3ed62026afcdeb7c33c7aae0bbaaa357e8d67a10457244bdacabf4f0001891b1e6bfec42e97c79ec505c7ae1b584cf47d4ed8f6cdfcad815b02a5496f6701b7fc5791e3650729b7e1e38ee8c4ea9da612a07b4bf412cefaffbab7ac74c547011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 1080000 ..< 1090000:
return WalletBirthday(
height: 1070000,
hash: "0000000000e69217b151ca8349e3c9f0c5406877554924d7a4f90fb6434bed9d",
time: 1607482606,
tree: "01ea25320fb5dffce1469a9018d2dbcd02bc16350761c1b24ef1f7c282ff3e70070179ccaff1ff2218010dfdb5e7cd8ab67c27c0f578fc94133fa2db58cba2a1b83112013d996c5be4fa4e5d75fb2f782f02dbaec8582a86a4a404397c2ed5bbb75b1660000153c736227e8f11677599ac536a2d19a2000035609833788b19062cbe075ea20200011a38e1599c81fa7039f159cee2ef7144f23c729ac1d235d1d81ea111ba1c8e520000000001aeda840e11db19f50b7b64c54de8a389e84a5e64e8c3ea8f4861503f587d9b2301802a64566b4a1fa471e350bd86ef0409f6b4712a8fdede1c537347f41506884100000103bcde16c3ed62026afcdeb7c33c7aae0bbaaa357e8d67a10457244bdacabf4f0001891b1e6bfec42e97c79ec505c7ae1b584cf47d4ed8f6cdfcad815b02a5496f6701b7fc5791e3650729b7e1e38ee8c4ea9da612a07b4bf412cefaffbab7ac74c547011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 1090000 ..< 1100000:
return WalletBirthday(
height: 1090000,
hash: "0000000000a48d9a9ec16a0ee42afba830507824086335e81290a55dfbbe0a0b",
time: 1608990684,
tree: "01bba893b54492e05be51cc957d99591f60e3c30b7bbc134f4a79e1219721d023901ed7c0412fd24ccb7919323fbfe9af815adcc0c4e29e581d5e10cf06ebc5af823120001f98603677f74513affc6586569aa76c60766b4249a25118ddcefef18698a2c6300000001dd255f2e4e75b7eef0d5b4c077025792a979fbe44e4b7fde9a1273a3c4d6450401aaf59d640c3cd74fd1cb67396250e4b536de1d300a3c17783ecfcb5ddeec9d3a0001d94a0cf0b8ea2f688b1e107cf6a013747f5f0af6543552291adda1c28668da6b0001ab131afe01856dc81300246b7df2fdc556fcf764cb3bdeea33e83507b706a0420000000185555efbf4f751c9c4a7068f9c1c3303bc33bc8bbd3847a6fa5b6d5b3d547f6101891b1e6bfec42e97c79ec505c7ae1b584cf47d4ed8f6cdfcad815b02a5496f6701b7fc5791e3650729b7e1e38ee8c4ea9da612a07b4bf412cefaffbab7ac74c547011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 1100000 ..< 1110000:
return WalletBirthday(
height: 1100000,
hash: "00000000022262ee215e5b6269cf159b4c9fb89b8a38f70873dde8dbc4c64669",
time: 1609745782,
tree: "012f5514d9c08767fcc3c8c2cb6d7e00cb68ff2eb69ccc869821f3c901a495fb5c0121aab76f6b245f76d9a89c82a5ba88c6b427bf0154f1689520e8a24fefba106812000001c2965bb8fd73128357ae46fd0451ff0d34a4b391a4a7d54c8d00dc00277b5b2c0001bb34e1eb64d2bad151a251de23fe7ab0d92c0d8125fb3c3aa8ce0a772ac1f83701c45242a1ce86ebb47c2abe6ef76f814b26f56b5883e5f0c520266563633e5d5600015b9ea4977075a83dad3e5e4547f93369f81807b960fa5d0377fea025dc47fd25000000000001103bcd926a1c140a15876ce5dd6bb4e0a32172f9fde5de340bd11fdd87d696670185555efbf4f751c9c4a7068f9c1c3303bc33bc8bbd3847a6fa5b6d5b3d547f6101891b1e6bfec42e97c79ec505c7ae1b584cf47d4ed8f6cdfcad815b02a5496f6701b7fc5791e3650729b7e1e38ee8c4ea9da612a07b4bf412cefaffbab7ac74c547011323ddf890bfd7b94fc609b0d191982cb426b8bf4d900d04709a8b9cb1a27625"
)
case 1110000 ..< 1120000:
return WalletBirthday(
height: 1110000,
hash: "00000000019dd5701deda91aee19f653d7d89983fec6253d5728b738ce1cc575",
time: 1610499871,
tree: "017f230e3a91ab56970595bc9037a6bb38b69390070076c46f9a3d364f96171701001300011ebe10c1b67824d2b71e48010a03f817d80963999e15e3b0364eeccac01e2e70011681651b3c5fe38d3c35445560b9a4599f9370e618c1e72f2b8a69efd47fc9720001ec4a3829e823478478cc46af80d6d4c6b947b422dea6b525b18986dde5698a370001b52370947e83349c731edf7c5ef43dc7f9b14ca47074dee8fd16b14c5663fe4a0001d5b32170d5ffab2c95ac01821260f970881c8a3fb5770aeac7739490135e152f0000000000000000000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1120000 ..< 1130000:
return WalletBirthday(
height: 1120000,
hash: "0000000000dcdf40c671af85eec40424e0475fecb06355fb5e37efda51f5dee7",
time: 1611253575,
tree: "01da06acb487d1ceaf8db4dc5ad8183bc8b4e9a4b020188336624bcd83adb7884f0013000000000187183a83d396d7d50514a081195ee24703202e0ec9e3196eb3bdef5e34354548000001d446400bb7cf59eac909c183eb8685cf6cc4517496708ad2bffd07acc46ce524000001e240979184856d63a9bbf849eaf06963acfc861af5a44a30e82193792d58fb4100019498b9b148ee924288e2225a474f2c9a7739500cb3c4821a52679f6a0a26d41000000000000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1130000 ..< 1140000:
return WalletBirthday(
height: 1130000,
hash: "000000000009bcbe15ce9e005c9ebda0a1c5213b9573ad29c3a86a1a9f3f6586",
time: 1612007546,
tree: "01cdb094138ff68752216908f08ac0978b612b5b928b1613ec79275071f1c968710013011f9339db47ecf1f7510683dc263074e79825ffb487fccdf81a9f4c748024024600012695a02e2d0d49c3cff6192b46d4c4cacbb86bbd4cd88b6bf65564070bea0f20000195556413de9fadd73e9d5ef1cfb905a021dfea4ffa2f1cb6204438c60d665b5b01c1125574436b79f9fc6364ec470f453570fe7ad0e313878b809a525224166d580199820bae76e624f5c06b7f744e6a6ed57dc03314e91aefd883648c7fe0ff1370014576446ae9961962903fbcd41c9d7ff2d8c41b77244ff39e2f1233286f95301001df16b424017aef9e9138169b7e183c2613ca6ebf9680fd27c9c280c194d0772f000001fd3610fa060d8eca861a55d6bf0042b7e11d67bdac285b4677c995f2b466276101e5f0a7191091bc4ea3b06cc6cef4644b426122d74b91cbece497f7bdaa19526401226d7b2448f34416550c5aa0730c58f1eb72ee60cb9e9d61bd66c81d31b5ef51000000000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1140000 ..< 1150000:
return WalletBirthday(
height: 1140000,
hash: "00000000006d9c69d8c4d7818dd2b9b106078317c6e881eab86ba41e4a546337",
time: 1612761940,
tree: "012afd078f200a60fe586c8ebb81208bc6b656f2c24935ed9ae483606368c6101c001301e0a84c415504116132c953c1885150a6335bc3293aa17c89626e02406f944f39000000017c0a218b969475ad665bfdea14177bd73b8510d451bd1f533f29d5f86f92a14201faee45bdbbec94f64fd8b641b3e2c1c473880b14a86134d766b9ffae127f0506014815011726d11513734103e47971902e4e8c1245ab2b96107184f2978a13cb2501eecd48ee70785ed9d31c4edb6da31287fe1b42082466c787262133017fe3ab210183352b54c9e84bed4c1fb4c31dc1bf690e88aec9f477f6e00d51a4bc918cba32018b702b3a1bb47c1455d5ca00cdb6d2eb72256f421937dee7d5453e7108c8df3a00017c41a5948f315986b60909e07a15c2639fb1b13a968aaf322d654aa1e823f60b00000116316e325ad5299b583121e42838f9cb432a88a7042cfeca8d36f8f5e86e234f0000000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1150000 ..< 1155000:
return WalletBirthday(
height: 1150000,
hash: "00000000012e01251034b1cf6ced448544f350f023280e3118cb23863affbb58",
time: 1613515993,
tree: "01a4948b191c1169242c0dfd9c287ce1ad06a681615ec99620fa5936bb05119d3000130001e9eb3a657f63031a386c64296e66b98374a0d74280132543535eb82180a5706801e0807fba775afd5acc8714c1c33ac709faee472841c3874ad477e57a01a01a4c0000000001dd716f606210678f0ce78fa535ba46a5cd1d0f22f7b237491e0136e71e51916400012278350ab0e251df819aa820ab100a1264bf5aa73c94bf5968730fa61668996001430989441afaafa2f64683ff0424b12b5051763ff094a88a4cc96cd00f09b8650113625bb6dc4092d25f906a05fd3e2f1a7c5df03381d0e0760aebc2ad0ecf0f0b01582a57901af4736388425e1bd26fff5b23fe6c74d10b1fd7145c46e57eeed609000116316e325ad5299b583121e42838f9cb432a88a7042cfeca8d36f8f5e86e234f0000000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1153000 ..< 1160000:
return WalletBirthday(
height: 1153000,
hash: "0000000001d06618d059c2c1d9a0dde0369cac8af75c9520409715f2a766b259",
time: 1613742458,
tree: "017aa8d47888728be9104e9dee586acf733b86fb244c4d9abd4b23d3b8f15b5d0b0111cf472e9ddd29f30ad95cf4f0fb7e587cc589735cfc9ec5a36a11e7d3394c711301fb9760d76283fc1af4195cf7d08a1f661cd20ca5201585451e877af846aeb6010000000001dc7dabd7bcce76a04412dbc9ef145d3d10eda33b5f644738c51286e84112c00b014d1745efddec53a2c5f23adc231decbec7a03c72ab4fed682d0affaf29584403018f8c345bf75a7efb9521dfc3cd6192b05b01702fc9a88f9be949a92d9f429f6a017b5ccbfa88f3523ed78b79f0cd86b883a096fb9b829c2a13000c8dee9ac9c72c01deeb9380b9491c7e7d59075ad35b8c8b748ba7d0337a273c3ce2a4e4179c9a2000000001bf57fd5f3e010a317aae249ee1c4583acc2688c9c22f84710f0173cab1f151560116316e325ad5299b583121e42838f9cb432a88a7042cfeca8d36f8f5e86e234f0000000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1160000 ..< 1170000:
return WalletBirthday(
height: 1153000,
hash: "0000000001a7bb6c535053418e8e9e1620c3e5611eebcb15218a0584754e8980",
time: 1614269669,
tree: "01ab89bc17a2fae59a5170033dea2302d8825a71a0e3fdb1a01d50c44fae59cf2a00130113607db0515d576fdaa165b61e9bbebf997bbf039ceb75aa04ccb3dffe492e5f000129140c523912d51834243412016078da091020f5c02bd498cba160342d20b92101f842c5a07a703b080c4d73cfa95460265b10bbb6c7dd5ba4cc50c7e24c4f380e0000000171df72fb201bb6c7f4fb3c9e06ac94ce0eb0f8c0259719d071587c3e5a74e00b00017010f179ca3f1dbb0865b00a418114dbdd67e031e430ee1bbea1b30081f14236016068bc4c06705014dae9c2a5f86f6734b08e39fb4ebd21366531dd93c0d0561d013ecba16781a5b5f4837c648de2a32f96c3d635a3b9e3630dc1bd1b1f4276be170001bf57fd5f3e010a317aae249ee1c4583acc2688c9c22f84710f0173cab1f151560116316e325ad5299b583121e42838f9cb432a88a7042cfeca8d36f8f5e86e234f0000000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1170000 ..< 1180000:
return WalletBirthday(
height: 1170000,
hash: "0000000001225d341f424c445c71b13872ff89300210594f3d9d405ead56f539",
time: 1615024297,
tree: "019968e9b4725455dea88d986b33458d199353a26f1349abbe7f39c3d72f82365701abcab1e8db711ee75949326fa6a0ad302776ff40036cfb4c1c770ea430a1af51130001352edbeb2884d8ed1f39c18125493783d76f495a88fdb32c7e5d7e61de1cfd7001b6966af9deaf4512b7922f65ad099fd11f1c3d34d80c93bf4e6d9aec18686d5201727534576ffd6b0cd7146d0e3516b3c9836e9ba5965e35b35033a3add146254901851e9189feb9e5f62c2df5049c930d0438083c86958cd179543156ada7da910f01392e342052ef08587ebf642bda8e3948b437b915a5d1856d59ced86d9e640a5e01199e767f23a7d41044303fe914e98c9b059b9ce0b85b37b7fa26e43d4fb5b72d000000000000000001089a1f9d50a037cc66aba4400b1703bcbb66f5f2993fd0dd3bb726e35940916700000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1180000 ..< 1190000:
return WalletBirthday(
height: 1180000,
hash: "0000000000521c0d55ce1765092caff595acb5d546147b192fa9272051f55f42",
time: 1615778593,
tree: "0102a70ba9e31d6c24be0fc283577072d815d418da5e1b14cc81923f7bed308460016d9d5c674c15bdaec54c70d528e94be910994213683e3aac2fc94092fd8b4a5b1301dce7f293aee6c2769fe616dd47d46e79b51568c8bc08c67198b20d28eaf12c6f000001ff83e392690a332103433465b2034df2ab6cf35c164149a3951bf0d2bcf2a96601d019ed97502d718643c32851eb1acf6307861a3fe0ce3174697b0c2df4568568011d8eb058dd0a73a4314e04f12a6de50dd18879ee891db5a20c890e1c707f6f01000001cda4d5ff76022119fed8ffb94b8d3a26a0db37a1a886a0f31a57d1c0ce03f106014fb59c2d5dd4cc176d226c57b48d4dfc4d200088d5b69cce675f84e885ee5c1b017d5b561bf80be788ebf12e901e4c544cad95e24d0b21e6145e1718ec9dbfe91101678fbb171e5715c63bfc888d345e755c69c6dbfc2818f05b6e6ca32211ffd44400000001089a1f9d50a037cc66aba4400b1703bcbb66f5f2993fd0dd3bb726e35940916700000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1190000 ..< 1200000:
return WalletBirthday(
height: 1190000,
hash: "00000000019caeb64ab8caa12e1dcdd9a8f391b063ec252887c91526b7ac5e0c",
time: 1616531745,
tree: "017ae2fbedf5cad68ee80df0ae9caef9e0168914780bfd14eae016e2fb89068071001301c78a8f9bfddd9a1f0076048c48d1d58298ac6f4368472a39b0b240d540117c4301b58c9284084704437af784307ab0a334dc9c7aef588bf7d26491274d79c4471301b0af0fff110293b555f17d5ced0a598693ff4cde3e680d988c6ccf498846753e01bb9d0f21f621448c03ee49de4ef3bf0faa4844544f9668197ef5921164d2401601a15d695922c5441e80aa770861f91a97dd460561515d32c9d06bd3c6f98ce26f000000014a772e6ce520bcedf07793ded6148fd3415ecbdd89c3efe183b6048f1fb4791c0001e281c5ec71bc1a301ad0d285f6f1aa2552907645b02f9d43160f5354c2be7c63012b4d8d83df48c8b5c35752268eb71a428aa05103809a887fb36519dedbc8de27017b610946256293c523b36cf95ec60f2c346d866d98d1276bbaba22e46815516d000001089a1f9d50a037cc66aba4400b1703bcbb66f5f2993fd0dd3bb726e35940916700000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1200000 ..< 1206000:
return WalletBirthday(
height: 1200000,
hash: "0000000000347d5011108fdcf667c93e622e8635c94e586556898e41db18d192",
time: 1617285467,
tree: "01dcc15a1314130c3ae61401ea76c0c1b32b0c44d8486fb6cb8764af9f6dc03d540132d6897fe6cbc340c786a129e69aaac499ba9ae33cebc0ae6163d02dd15db4061300000000011b153a8182d97d204f5ddf0cdbe66543d67ef3b25dac5602987d4dcb57f35c260001a3d62e7611681256eb34d5945fbbc085ccf1d04d6a507295c3c9724f6e899069017fd5efaf2ba1e3c53b0039674b6667e401c83834d53b0970c7ff3a6dad684a540001c77d47e4819c69c3a473b8e4c660bc73c2a4fc0a067e5ad21c6fba9aa031c96e00013729a1708bbe29fcd683e3e3337e8b8ded4fa6abb24cb7bef506168be7fe8a5b0001df26abb60966dedb257d90ef08aa7232474229e08e62ba390336a07c4775a7260001089a1f9d50a037cc66aba4400b1703bcbb66f5f2993fd0dd3bb726e35940916700000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1206000 ..< 1217000:
return WalletBirthday(
height: 1206000,
hash: "000000000078454a0d74d2df9ae2ca53ee37bfa21ba5d761a96dc426eb3603b8",
time: 1617738149,
tree: "01f423310ab6f632a457f8b91f6c16ba6a0c2b49297f54462e5588d1eb6aaaa0200147dbb8e70cbf50002af16e9e75ebd32c1e5f3f66b43e88001965be754ea82a3e13000001cb1695d6e381645c49c9706709438c8a40cb667b7eabbce3669f293d2738e24d00012a8f5a54b81bb34bbf0a8e8bbff5217f17a423bd379ab08a08506744a6c0272700019827b9160f8772351b07ea603a48a6085ebc61692243ae9dc6b5118c1b5be347000000014226899cc196086727c3a53560a6273406f499e19d1b57cfd6018be889630e0d000180541ee92782f67894645a8a976ccd0934e37c13fbbc7cbb501b7ba78d1a902301df26abb60966dedb257d90ef08aa7232474229e08e62ba390336a07c4775a7260001089a1f9d50a037cc66aba4400b1703bcbb66f5f2993fd0dd3bb726e35940916700000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1217000 ..< 1220000:
return WalletBirthday(
height: 1217000,
hash: "000000000101d56be0c460d0e3cd780bf4eeeee79f98b2650ed61f2461ed0e61",
time: 1618567777,
tree: "0196abe4a8e73e641c8bde7f7d4c7455fc530758e5754b513ca76bc959757d773c0013010c2a76ab6a36beee5f415d06f0c4081b2569b8268123f00ac6a6cf95818dcf11000001f913b2dfda97da60e92d1cc81d0533f87794aa1dfd50bd668ffac7cfc1c1e2090001dd5879eeb7e652f8edf6458079cf06a4189700cb2dd6faaea03179a1d24d59050116769e0bf56d11a3fab9b728e76d131b177add630475992c0272ac1f6d14815e00019e4967e62633bd0d8084f78aa945c1a50bd571c71d06098f352a9d329c4d86110001a1e452b5cdaf030e7b4a75b30cbf4a920aa502d03c4b25af22c3ba815870a14700000001ece344ca21dbd3b681f167163d4792165efe8239390afc13378e50d044fee65a01089a1f9d50a037cc66aba4400b1703bcbb66f5f2993fd0dd3bb726e35940916700000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1220000 ..< 1230000:
return WalletBirthday(
height: 1220000,
hash: "0000000000751d7ffb3aac6f6a66ed01aa4e991a96162c1749dc556e50fe6df0",
time: 1618794113,
tree: "01c3bbf34ce189a5285144c79cc37c4e76385b803947819ea8bc43b1e8eb2c020801861a52e2fb19b150b0b7c7d7f879bd1ac4fa3a11ac9763db4f837f4db048896413013ddab8738a0cc8e00e96c7487d21a9771a7986b7e1e5d5fb0348d46caa18360c01d6b0010e9664a01a47a8acc9bf073255f6fb62f617cb491b249671da85001862000000012fe6dc35a5d51af73b73854855f9861775296a9c56d6aa9455be2762a101d7390168ee29d7b083e5af0d1895b2832a4fc63a9c7b6cea37b75d17d28e6f5842ee0c0159781dcd759c87f8bc8622bc19f9a8732c06b52897bfb6e0ddcbadb111d6a95601036e008ad224efaa9833fa9e790192dad7aab0ba71bf872430f48ba6aa0d1d1b00000169bce4bc91631cf6158d978b5ce6ad03f3e4cc3317c28964b575ca736f8b4d68000001ece344ca21dbd3b681f167163d4792165efe8239390afc13378e50d044fee65a01089a1f9d50a037cc66aba4400b1703bcbb66f5f2993fd0dd3bb726e35940916700000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1230000 ..< 1240000:
return WalletBirthday(
height: 1230000,
hash: "0000000001bcfbeb53fd5e9647168265bc5fc8e8622049b9cdd07098f0f51601",
time: 1619548843,
tree: "0164566f774ea1f6d7cf21a9fbf9cb3f2e7d1e400097417822a7c233422619c3710013000001bad8de55d9adf4d4ff08f4ad172a5ee80aa0049974c5227d2b07474078f73c2a01e8d5303b72f034efacb9b9aa0697aa5568bf6116f2fdc1e528c03b76ce569c340000000000015334d52667d65b8ff3dcfb3d6ed72c46ad19ea9112813aaf344a3e614eb9012600016cad8c39b711691f2bda74017894c657555a8bf7ef913931ac4f7ba0b48a30120121c25bceccda091622bfac1b7973ffaa638abe1f334b3b56f48dc93dc549c9070001ece344ca21dbd3b681f167163d4792165efe8239390afc13378e50d044fee65a01089a1f9d50a037cc66aba4400b1703bcbb66f5f2993fd0dd3bb726e35940916700000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1240000 ..< 1250000:
return WalletBirthday(
height: 1240000,
hash: "0000000002473bf56688195f05b6f5acea0f99506fca40ae72f2ab8c1fd7390d",
time: 1620303759,
tree: "017b7c743693588568510844e4bc181d12ab6433dced0542d149cbec2b96ba526500130001cb8eccc27eb266385f9e4b880ff337b2ebdf10238dac74414fde8937dfa2264b0001bb0cb6201a0d003f1e4df17cfd4815c382ced6bf038468873495ff5c9c25412501ba626167f23eb767c229a0498b37e8322326779a3a6454ebcefd639056b3e64400013ff350f9e880271ea2c713c509491605ea24589c369262c18c417fdf1027305e0000000001849b1538147707b1c880e7eee02f29ada52e8a5a6c3a9027087493f41bd8304a00018e7922ca798cd3e26d3369ca2425ec19baa7d79407a979ec1090ae48fdcd094a01ece344ca21dbd3b681f167163d4792165efe8239390afc13378e50d044fee65a01089a1f9d50a037cc66aba4400b1703bcbb66f5f2993fd0dd3bb726e35940916700000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1250000 ..< 1255000:
return WalletBirthday(
height: 1250000,
hash: "0000000000f3d2c352c395d66866032bcb67094228dd4a27e561b1c399ea612e",
time: 1621056898,
tree: "01c9a0dd6f6dfaaafe6ae4b432c2d1c41d2a73e564c8cb6d2c5ab637c7001a2456001300000000017da32b486a8ea9f13afb93b99d2b1de69aa969e7c2fd7b9ee958bece70c08d6b000001b3a4486b176dfcedc0b3d9287c0333ff464ecbd02bac7c89bcda7932e6a0a36100010d451c18b56877b8a11cb401ab7024c82b9669ede862a53e461087f57220035001a1c5260bc4dfe010510b8135209c6f64229965f71717f1e693abdcf88a58f36700012f0bf70e372e536fc3b76ecd7e2b69eebf2fbcf71b828c64b0a8b99390fbf754018e7922ca798cd3e26d3369ca2425ec19baa7d79407a979ec1090ae48fdcd094a01ece344ca21dbd3b681f167163d4792165efe8239390afc13378e50d044fee65a01089a1f9d50a037cc66aba4400b1703bcbb66f5f2993fd0dd3bb726e35940916700000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1255000 ..< 1300000:
return WalletBirthday(
height: 1255000,
hash: "0000000000f34f274737e653cc31122e8ba8ca9865c09b65b3c2ecfb2e9687fd",
time: 1621434019,
tree: "016f51c78a2c55fef567e8deac7cb82b1f62f9ee6f5fdea27fc6fd9d1955e30353013f25aaa8aedcf10cd63b622d8c7dc21eb7b30504f99952bbc8efb437ffc482131301d0fa036d389289e37709f7f01d09e689cf55e989ea9d07440d593f21929f960801f69330a08f076f55f5db32aab6f2d1a2ab23e52a9a4e4fbbd21b8204ff23e64d00012f1469ddab73380dc3302f1cdbefb508141e2689a83b754fd9970037eb04fe6a00000000014ba6ac078f45c360c912ef828c138e4bd7d4150cadb2a498a32ec3fe7e22cc720001638de702094b20c64bc4b046cf7724634096aa192b155d191934120653734414013027101973e524ee59f21261bbf9fc152a61856a00f876a7c2b4dec71d50e969012f0bf70e372e536fc3b76ecd7e2b69eebf2fbcf71b828c64b0a8b99390fbf754018e7922ca798cd3e26d3369ca2425ec19baa7d79407a979ec1090ae48fdcd094a01ece344ca21dbd3b681f167163d4792165efe8239390afc13378e50d044fee65a01089a1f9d50a037cc66aba4400b1703bcbb66f5f2993fd0dd3bb726e35940916700000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1300000 ..< 1310000:
return WalletBirthday(
height: 1300000,
hash: "00000000027222bdbcf9c5f807f851f97312ac6e0dbbc2b93f2be21a69c59d44",
time: 1624830312,
tree: "01f5a97e2679a2bb9103caf37b825f92fcd73fff836234844dfcf1815394522b2c01526587b9b9e8aeb0eb572d81fec1f5127b8278ba0f57e451bd6b796596940a2213000131c7ff90fafff6159b8fb6544a2bcbba6c102903158fce8f9a9d3c6654abb23300013555cb7f4f79badeaca9bf2dca5a8704f0929053d50e95c03002f9a4d5286c3a01ad3557e11c1607ec888dc84f5f8899c3c79fb1f50b613946452ec7dd5e53763c0001c4583f4482b949390dba355fc8fa63019c83acd644ddd633cb50211d236f870600000001088da0d78eefd0c222507927e403b972d0890d0c31e08b02268fbe39ac4a6e170001edf82d4e2b4893ea2028ca8c5149e50a4c358b856d73f2de2b9a22034fa78f22012ffde6dccbef68b60cd7b4e7a8fe7989f5954fa4bacad01b247d16b9bfa5084000000125911f4524469c00ccb1ba69e64f0ee7380c8d17bbfc76ecd238421b86eb6e09000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1310000 ..< 1320000:
return WalletBirthday(
height: 1310000,
hash: "00000000011ced7ee934fe237a80b74f04901db85fa82a4eec008fbb11ecf2e5",
time: 1625583320,
tree: "014be5784c617834157df657bafbc419ca3930f25deddaa9f29fc17483b235524800130001cc95eae2b1c3759963275342e56f1b71cd0bb6a4e2c0405f0108eb96f668851201f559a0e5f1b41af70fd6daccb0a48c3c178dfd8d25c09ff5152abded864a264f000000010bf2a42d0faed94259d4747ef48adaedf5772ebc93211f89be1612c1a9644603019f067dfc649ee5291bdf3caf7a307fb939eceb716c5050b63f620f0e41e1724400000000000001b35fe4a943a47404f68db220c77b0573e13c3378a65c6f2396f93be7609d8f2a000125911f4524469c00ccb1ba69e64f0ee7380c8d17bbfc76ecd238421b86eb6e09000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1320000 ..< 1330000:
return WalletBirthday(
height: 1320000,
hash: "00000000001dd2deed141caa32a167fc9c11dc2d95f76f7cdda9f50326411309",
time: 1626337252,
tree: "018095da27911b257bdeaa799f1c36be3767f8ef268e1f232263e88df0aa7b4f6300130001e4e456c3aa306bf54a77176e2462715076b3586fe36716bfc3ec113a239fdb3c0000014e4fa821d93b8944df3d5500fd71b3fca0f4c2a6add80137f7b3379fdc56a4260000000000011cc990619b9371b0240cf3038e8b3b0aaa6c50e78db250a77f0b4c63f49d811a019b4b90179cf9bf8c7556caacf6acb77ac97620777d2dff5be661e576cac55f22000001b35fe4a943a47404f68db220c77b0573e13c3378a65c6f2396f93be7609d8f2a000125911f4524469c00ccb1ba69e64f0ee7380c8d17bbfc76ecd238421b86eb6e09000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1330000 ..< 1336316:
return WalletBirthday(
height: 1330000,
hash: "0000000001126cdf85b463d086c6bf54d67094f6e17db3b08e38c2b4b16de926",
time: 1627091654,
tree: "016cc0651c73617064bf6de5962c99ec81fdce76d58ac2aab8b881e3b35991486d01593438b57eb9cfa76d5ea965b77a0304ff46163846c7c1ffb2695419a8dbfd4c1301e9766721a57a35e08763a27244291cb7db2ca67a711fd0569fd78aa675a21e1b019a9908d737043f786d7cdddbb22cb4d026c6c3221d34bd82bf4dc55acdd847640000000001de097ad39006362760b514f69a3aa88c66ada02085de26de23b522167df616320000000001a090ee174239a34a5d684425d09006d238c6075a61c5842d0fc26043f09ccd7001a2b7ee187c7b8ce18ebda8600bed7695b12f7d35ac971ed6ee67184a7ceebd490001b35fe4a943a47404f68db220c77b0573e13c3378a65c6f2396f93be7609d8f2a000125911f4524469c00ccb1ba69e64f0ee7380c8d17bbfc76ecd238421b86eb6e09000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
case 1336316 ..< BlockHeight.max:
return WalletBirthday(
height: 1336316,
hash: "000000000196f12f0d91c95f0acc391454bf81901e95645e5fcd1935bd59ae27",
time: 1627567384,
tree: "0178d99ba141a858548143bfc60443bc965c8abcf4c0be7eca28b7681dfbc64c400013000141a76d7e56cf73013cb8c6549f90601a3d0a0c4057ca4f2b5515986c29d8710b01c21a76fc8075ae365db50bff0a03d674ab8dddd6e167a1c61125168365b40e40013338e3fef636235ace2523ae0d458508e795d04d7c49a77fa32032f45c482714000001fadad4c3da753327273cff5f827ac6a2da9cdf9554fb8e4ae1d73b0beb2b4a5a00012510c0b1bbca57be1267cba3c8e8e28c7457a3580f32fef3ad1ab5c117263e6401ea5e9a0276d6f23b8da7c2006a85277d92badb145c62334243205676b2ec971f012965494015cdab2ce010c1ae4ea88306c286128275de391dcf57d3fa85be7e1b01a090ee174239a34a5d684425d09006d238c6075a61c5842d0fc26043f09ccd7001a2b7ee187c7b8ce18ebda8600bed7695b12f7d35ac971ed6ee67184a7ceebd490001b35fe4a943a47404f68db220c77b0573e13c3378a65c6f2396f93be7609d8f2a000125911f4524469c00ccb1ba69e64f0ee7380c8d17bbfc76ecd238421b86eb6e09000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
default:
return WalletBirthday(
height: 1336316,
hash: "000000000196f12f0d91c95f0acc391454bf81901e95645e5fcd1935bd59ae27",
time: 1627567384,
tree: "0178d99ba141a858548143bfc60443bc965c8abcf4c0be7eca28b7681dfbc64c400013000141a76d7e56cf73013cb8c6549f90601a3d0a0c4057ca4f2b5515986c29d8710b01c21a76fc8075ae365db50bff0a03d674ab8dddd6e167a1c61125168365b40e40013338e3fef636235ace2523ae0d458508e795d04d7c49a77fa32032f45c482714000001fadad4c3da753327273cff5f827ac6a2da9cdf9554fb8e4ae1d73b0beb2b4a5a00012510c0b1bbca57be1267cba3c8e8e28c7457a3580f32fef3ad1ab5c117263e6401ea5e9a0276d6f23b8da7c2006a85277d92badb145c62334243205676b2ec971f012965494015cdab2ce010c1ae4ea88306c286128275de391dcf57d3fa85be7e1b01a090ee174239a34a5d684425d09006d238c6075a61c5842d0fc26043f09ccd7001a2b7ee187c7b8ce18ebda8600bed7695b12f7d35ac971ed6ee67184a7ceebd490001b35fe4a943a47404f68db220c77b0573e13c3378a65c6f2396f93be7609d8f2a000125911f4524469c00ccb1ba69e64f0ee7380c8d17bbfc76ecd238421b86eb6e09000118f64df255c9c43db708255e7bf6bffd481e5c2f38fe9ed8f3d189f7f9cf2644"
)
}
}
}

View File

@ -0,0 +1,243 @@
//
// WalletBirthday+testnet.swift
// ZcashLightClientKit
//
// Created by Francisco Gindre on 7/28/21.
//
import Foundation
extension WalletBirthday {
static func testnetBirthday(with height: BlockHeight) -> WalletBirthday {
switch height {
case BlockHeight.min ..< 421720:
return WalletBirthday(
height: 280000,
hash: "000420e7fcc3a49d729479fb0b560dd7b8617b178a08e9e389620a9d1dd6361a",
time: 1535262293,
tree: "000000"
)
case 421720 ..< 425865:
return WalletBirthday(
height: 421720,
hash: "001ede53476a31a91da3313eddf4e41409fb7f4e003840700557b576024d09b4",
time: 1550762014,
tree: "015495a30aef9e18b9c774df6a9fcd583748c8bba1a6348e70f59bc9f0c2bc673b000f00000000018054b75173b577dc36f2c80dfc41f83d6716557597f74ec54436df32d4466d57000120f1825067a52ca973b07431199d5866a0d46ef231d08aa2f544665936d5b4520168d782e3d028131f59e9296c75de5a101898c5e53108e45baa223c608d6c3d3d01fb0a8d465b57c15d793c742df9470b116ddf06bd30d42123fdb7becef1fd63640001a86b141bdb55fd5f5b2e880ea4e07caf2bbf1ac7b52a9f504977913068a917270001dd960b6c11b157d1626f0768ec099af9385aea3f31c91111a8c5b899ffb99e6b0192acd61b1853311b0bf166057ca433e231c93ab5988844a09a91c113ebc58e18019fbfd76ad6d98cafa0174391546e7022afe62e870e20e16d57c4c419a5c2bb69"
)
case 425865 ..< 518000:
return WalletBirthday(
height: 425865,
hash: "0011c4de26004e564347b8af218ca16cd07b08c4159b1cc9c43afa6cb8807bed",
time: 1551215770,
tree: "01881e4da7e4767ee8a144a32ab8a5719a513bb05854477773bb55e6cd7f15055201f8a99a3a5ae3528ec2fc0bda9652b6728aecb08bf364e06ac511fd6654d782720f019ef0b9bdd075c38519fa4ab8210fe7e94c609f52672796e33e3cab58b1602831000001f803bf338ff1526b2ca527288974cb9be3fe240a2eadb7507e46ba59eaddb9320129fc0148ac088a6aa509f8f64ef79fda92232020369b58a12b32c05b6f428f22015e3dd0950c442940bd015c2176f7c817f22104f54c61159727483188c539dc13000000013589be9e2d9e9e38fd78b1e8eaec5b5f5167bf7fd2b1c95c316fa366a24cac4c01a86b141bdb55fd5f5b2e880ea4e07caf2bbf1ac7b52a9f504977913068a917270001dd960b6c11b157d1626f0768ec099af9385aea3f31c91111a8c5b899ffb99e6b0192acd61b1853311b0bf166057ca433e231c93ab5988844a09a91c113ebc58e18019fbfd76ad6d98cafa0174391546e7022afe62e870e20e16d57c4c419a5c2bb69"
)
case 518000 ..< 523240:
return WalletBirthday(
height: 518000,
hash: "000ba586d734c295f0bc034be229b1c96cb040f9d4929efdb5d2b187eeb238fb",
time: 1560645743,
tree: "01a4f5240a88a6eb4ffbda7961a1430506aad1a50ba011593f02c243d968feb0550010000140f91773b4ab669846e5bcb96f60e68256c49a27872a98e9d5ce50b30a0c434e0000018968663d6a7b444591de83f8a07223113f5de7e8203807adacc7677c3bcd4f420194c7ecac0ef6d702d475680ec32051fdf6368af0c459ab450009c001bcbf7a5300000001f0eead5192c3b3ab7208429877570676647e448210332c6da7e18660b142b80e01b98b14cab05247195b3b3be3dd8639bae99a0dd10bed1282ac25b62a134afd7200000000011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 523240 ..< 620000:
return WalletBirthday(
height: 523240,
hash: "00000c33da2196f0ed1bda71043f671fc69a0212e01f892653e212ab358f6b79",
time: 1561002603,
tree: "01d3e02bc1c2d66762f370b329a3063067701ad66c44b40285686bc8ff25f5616f00100154bff87bd0bda3b70a6d7754eca261de15fee3cd9bc53073a232e07fc3261e27000001a54dcaccb4c5e578aef89f2a3b4e3c3d8a487e6e904c5da5916118d721948d07000000000118fa9c6fef4963049dc7002a13bb0021d5e950591e48c9e5f2cbd1199429b80401f0eead5192c3b3ab7208429877570676647e448210332c6da7e18660b142b80e01b98b14cab05247195b3b3be3dd8639bae99a0dd10bed1282ac25b62a134afd7200000000011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 620000 ..< 680000:
return WalletBirthday(
height: 620000,
hash: "005f97953c8e1265d6b45f4435ffa32918e53e8f0025c286a4080c3eab167197",
time: 1569572035,
tree: "0170cf036ea1ea3c6e08432e18b6a372ca0b8b83671cc13ab0cf9e28c182f6c36f00100000013f3fc2c16ac4780f1c472ca65534ab08911f325a9edde5ea7f24364b47c9a95300017621b12e518cbbbdb7511ab423e0bddda412ed61ed3cff5be2140de65d6a0069010576153a5a2098812e7a028c37c3398e186f398c9b07bc199784ab97e5535c3e0000019a6ce2f0f7dbb2de493a315abf62d8ca96ccc701f116b6ddfae33870a2183d3c01c9d3564eff54ebc328eab2e4f1150c3637f4f47516f879a0cfebdf49fe7b1d5201c104705fac60a85596010e41260d07f3a64f38f37a112eaef41cd9d736edc5270145e3d4899fcd7f0f1236ae31eafb3f4b65ad6b11a17eae1729cec09bd3afa01a000000011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 680000 ..< 720000:
return WalletBirthday(
height: 680000,
hash: "00a4fbf54597d2f474f999576affad63f0ba2daa14c6fcd55c7eeec700107270",
time: 1573569367,
tree: "010a57f939a267f8b1e8b77288c783432e48fa95f7b22ead5e8ff46a788181453801d6457d98d3698a367aef4a2fe5675a575790d5d8081b731f979f0e64043fb7351001afaaf81d6d982b401444dbcf89e63c2583d234c1a60de17940a9b3a15f3494660001ba7acc730584a689413c44781d3b13cd497bfdca3fe27fb78cd9b50e9929906300000000000129e195df514840a20b95200b92d5b8d196b119cd6887508d8de077beffdbfe68016482af04b979e08e4e5760d55832292e55dbdd88143992f123840c8983db7b3f000001e3ec5d790cc9acc2586fc6e9ce5aae5f5aba32d33e386165c248c4a03ec8ed670000011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 720000 ..< 740000:
return WalletBirthday(
height: 720000,
hash: "018b71dde8c9b1ee3e79961c6e3536c79226f5d6e79bb35c9ed28dcb8cb78b48",
time: 1575943651,
tree: "012cfde48dff4f20ddc50a7aca3746f7d77920eebc8cf4ef53feac34cb8719c03a012c668d234aaa485862e1d06e46d6d7093c2581e2b9cda90aafd691d6e325410610014f3a875476cb8159d46fec1aba18c201c268cd61b01811b7e5bf83998fb8222500011f19160cc75325c090f3eb3fa0cff2d94e43e2713c89e7b02a34f6ed08fbcd26000001edc05305223f7f2839abc1dc7d900468349577d6d6f5c182ef3a81a848753b5b0000000129cbee0c11a827718f126d9e037155a9e173ee2d2ecf57dc68f7b66437d44f7301a113bcf163405e4286bc080ac55aa68555d2c9e63334e7b9a5eb756872f14c470001e3ec5d790cc9acc2586fc6e9ce5aae5f5aba32d33e386165c248c4a03ec8ed670000011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 740000 ..< 760000:
return WalletBirthday(
height: 740000,
hash: "00163c394a1e545b4c777fc91474d92becdd0fe9300d38fb3563997d026a54ea",
time: 1577389695,
tree: "0135ee37f83d0b924eed58bcceb249a4977dcb21495561b97bc747a272ebe5d6580010000001fe65cfbb8a76e0d29ac94e5ada80c80b607d1addfc287754f37ddef531eb122500013a1d604d978f716fcb2887cdaa3c582a608b795ed1b3c57998cbede2be479931000108ffb0fbc6b653305b37cd5568b85112b996cd514fe97ec73f7169dae0cef05101baf5541e853483315273c25c1956d233513c3dabd8741972136b2f8f8cd89035000129cbee0c11a827718f126d9e037155a9e173ee2d2ecf57dc68f7b66437d44f7301a113bcf163405e4286bc080ac55aa68555d2c9e63334e7b9a5eb756872f14c470001e3ec5d790cc9acc2586fc6e9ce5aae5f5aba32d33e386165c248c4a03ec8ed670000011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 760000 ..< 780000:
return WalletBirthday(
height: 760000,
hash: "005ee769f3adbd0b24a63e8e4047200e038c38df277544d40c23ac1a88c1f37b",
time: 1578766903,
tree: "01470a1a4d29374e074f07a646b95dd89892d9b84d235a89ecc9d5a52beadce901001001311898ce56df0ddb10dc573a54ea06d11415e72602daa80c01f888fbd4a9a734018610afa4925cdb8bd4dd75a53ab69a74080322cae53c630ac02ce00b09d3171601bdfbbde5011bd6c0620ed2db3e01d5daa2ff8bb5f3b58687d265dd33a5681d530197e268c82e56dfc62aeb54586a2000766da8078f09a2d15fb558ad05664b4c5301aa204407034ba59fce0eee6518688585e96b0f10befd595b8e68a8ae15328a51017389398c5634242b03ef811f6abf224df9e6fc6d4393139e526dca4cf44dcc2c0000017de4c2c210c617dc61a43e124cab93e4f6143e1e9e46c2e55a541a9781cde43c0129cbee0c11a827718f126d9e037155a9e173ee2d2ecf57dc68f7b66437d44f7301a113bcf163405e4286bc080ac55aa68555d2c9e63334e7b9a5eb756872f14c470001e3ec5d790cc9acc2586fc6e9ce5aae5f5aba32d33e386165c248c4a03ec8ed670000011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 780000 ..< 798181:
return WalletBirthday(
height: 780000,
hash: "0104238cc440b6bf05b86a1b00d794c6d88fc61b8c416124a971fb5ce94b91e6",
time: 1580205978,
tree: "011ed883b7eddb4783eee5b73ceee4c78413e1f6f9db3d88d1007f5fa62292955c001001861feaeab59bc31cd97ffc89467877abf8b9fa157bc875907eb90d6e8c723325000000000001ccc21a1d581eb6d3f35729f202f0014a59b4f9d41d92d44316b381f57dc8356b01ec0f418f21af87c0e0846b318be838bd181f25b708ee2b2fa030468399fb7932017de4c2c210c617dc61a43e124cab93e4f6143e1e9e46c2e55a541a9781cde43c0129cbee0c11a827718f126d9e037155a9e173ee2d2ecf57dc68f7b66437d44f7301a113bcf163405e4286bc080ac55aa68555d2c9e63334e7b9a5eb756872f14c470001e3ec5d790cc9acc2586fc6e9ce5aae5f5aba32d33e386165c248c4a03ec8ed670000011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 798181 ..< 800000:
return WalletBirthday(
height: 798181,
hash: "02936aa4f8b6b2caad7cca19a866158656e37edfb0f32e2a473dc278fa634b71",
time: 1581521064,
tree: "01901ef0f4221f8a02d5896fda6f78cb5578fb8e9a5361d5689bfb3b6ab92072320010000101c5d791d8748f0ab0ecdb48764de29c470cc74f5d95b5a1f8cf0830bb059b66015af654e998c75460e9c1f5ba185589c53c383167e66951cfe7684321b7a77e5c013faf6b3f21f03982ada477bfddc95b18e63683c497b2f4630ab453623c28974c01aff3253410a6601ab4b5b3626f2121cb77399c634b1774a4c63f415598d16b0c01a6158d0a1a1bec9dadc601b140a9fdfc7bdab7e232739a3cc0e0e46bbe3ef44301ccc21a1d581eb6d3f35729f202f0014a59b4f9d41d92d44316b381f57dc8356b01ec0f418f21af87c0e0846b318be838bd181f25b708ee2b2fa030468399fb7932017de4c2c210c617dc61a43e124cab93e4f6143e1e9e46c2e55a541a9781cde43c0129cbee0c11a827718f126d9e037155a9e173ee2d2ecf57dc68f7b66437d44f7301a113bcf163405e4286bc080ac55aa68555d2c9e63334e7b9a5eb756872f14c470001e3ec5d790cc9acc2586fc6e9ce5aae5f5aba32d33e386165c248c4a03ec8ed670000011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 800000 ..< 850000:
return WalletBirthday(
height: 800000,
hash: "00599614a7795bbef99a598cfee887782900fa5cd95cd59900b8d6582bdc17a5",
time: 1581643886,
tree: "011ba0f16f59489a9bf9cc46c3ed1108c1dc0ff6e40f3a38def472c3229a96925e01b0eb758757bde323a6417d98365ce8f6299b0fa3de615d6cda68689e6a81573d1001438b40ff7357432d987d6ef4826fba35d38b2db531ea842ccedd4916a6aff9580000017cd705c293895c8b4613a3de3ad3b8d43ae05fff808882db4c5e19917e2f346d00000000000000016f6df9b95ef63866bdf0e8b4b97701cd09232ec3e4e240808c0546d01bc7bb0501e3ec5d790cc9acc2586fc6e9ce5aae5f5aba32d33e386165c248c4a03ec8ed670000011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 850000 ..< 900000:
return WalletBirthday(
height: 850000,
hash: "003b66bc3528dc295193108caab868e0f3b93d13db2ddcad5486225fb2b83d83",
time: 1585012771,
tree: "01e3bd906376b563d184bfbf6616e220f895001b7ef9d26bf38c6cb5c71e57a42b001001d848adf8c38d113140bb30d306b0761da6987e25ffc0d82faa63c2764aab120301de3e6a35d09192cde3430860c70a534d7b63e95a726fab052de2a9befa3cc3320189b958fa030131bb83385a3e3a8b187a166dc1b3a02050f2d2fc20788536c30e0001cb8770ef198e7de60093a339afbc561c16c16749f9f96751c2fc58a22d0ff36f01f86ff70dd512f7075d02c5ee6e28a8824832d08025a4cfaf4c1854f1fba5da10019bcac1b44a27de2c4528fa6f4b3432913511b219cb3b29d137cac0236a3d244800000000016f6df9b95ef63866bdf0e8b4b97701cd09232ec3e4e240808c0546d01bc7bb0501e3ec5d790cc9acc2586fc6e9ce5aae5f5aba32d33e386165c248c4a03ec8ed670000011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 950000 ..< 1013250:
return WalletBirthday(
height: 950000,
hash: "0005050d2ce31b9b925c7ef4ab3d3166d5833bdcfee251294f29072a2bc0f75d",
time: 1591609525,
tree: "01f0637235c4a699d49ba996457a6c4eb7c67edd8270948065683deb19ef218363019f65a9692cefc7b90b42c1538ac1f38f7a7598549089c4561315b482f378523010000000000000018d30d0039277b05ab9e0c3990d53037c45892bf17af2d04fef40ed48c164ad2201ff5d86bbbe360e31378e783b740f8b05db2cf4246b95aa3851d22ed45554750300010cefb25743d5dd6062ef3afba438731cd5b35befc1038ecca3076fd205829e550001c19052386d8bbe3c07a1faf302281d67946cc9547e7e1890ff56b3a3ec69c0310001be53a6cd33da0442c7c6362c0172241f42e13c6dc893436a661a1cbf49775c1f00011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1013250 ..< 1028400:
return WalletBirthday(
height: 1013250,
hash: "0017b3c49eea14e93f69adbc7a8f24eef3e9645f92e3b8d5e4091e1d5a4824b7",
time: 1595516064,
tree: "01d45e95007f8f97fe3c6a297a9d4bca917772e545fbcbb61b4f42d8a743eae31b0010013d7b7da2e6792dbfc6360f0c13a1ba879aa51a498c6dbab87aa57cef558cc35a00000001f945c15602617327026e3e0f231daf91570b32f7bb766f65e7e82131a911cc3c0000013173e9983fbd7a396e192e520d163be06cdd28abcfeba46c59dc62a400f589080001e7d5b00f0758cd3b7407c6d13e23d1a59e3f510c3dd3a4a8fc367a5305673b3f000001c787f900940720a3692e5694b085d5409dfa966017a6a48441c7e4b423b3144701be53a6cd33da0442c7c6362c0172241f42e13c6dc893436a661a1cbf49775c1f00011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1028400 ..< 1130000:
return WalletBirthday(
height: 1028400,
hash: "0006b94b304009f8a6287aa48021aed26582ce74d387c2c452aede86566179a6",
time: 1596480151,
tree: "01ac95378779cf56f0726655d248f95d63e07316ab67651ce357b346f9a7adba300107d7544edbe7d0522fe523df2ff804fc9f33f4844dd29e86a23fc7aa1818e237100001f8779a159482fd3a28c640e6d48ddfb37a44a26a102aae3822f32d2de22a1c70011f97534315f1800961bc78fcd1495e3b8047bb227e2776080fb31be6cae14e73000000000001fe15295e017fc2b8ba4ea1b7e53dd15f19860d10e7952905b7598373e143413e00019289038516ce3d6038cebe852ab5e32f7a1966fc79a1e41c7cb6e67e5a71c33d0001c787f900940720a3692e5694b085d5409dfa966017a6a48441c7e4b423b3144701be53a6cd33da0442c7c6362c0172241f42e13c6dc893436a661a1cbf49775c1f00011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1130000 ..< 1370446:
return WalletBirthday(
height: 1130000,
hash: "001f6563cf2863d36501dee00e41795f2fdb482970ea5f648791bbf7da4e6860",
time: 1603070117,
tree: "01b00c3e6d98e706fdb2d40f082096505aaa70fb87c067baf1a8a6d25cccff7258015a5334276509c93b855db0c2a1252e2ca725821c9274add1c2e92631bbbfa12b100151ba8342564941385670cd7346dc753bb5cc61164f000f65044cc09baa175917019ed834b8b9c8ca58969b3f239d74c2dd4a7d0a462afb1e856cf76209b866eb660135de9af32480f38eeca478a33a95f495abe7470e93d5aa4813fab7ea4fd12c4c0000017ce3fc7ebc2f8cfc2e1ee9f8e92b6e45065679ee3b48b5b2f0ce053305f5a95c011f1e8fe8f4a1cb5a700614218b8bebf2113c8a660abd255f67448b684b82d76e00000000016d559de7a1a382349cf97fe01a2fba41a49bb5e3b306d9ff8c2bcc301c731c00000001f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1370446 ..< 1414969:
return WalletBirthday(
height: 1370446,
hash: "00357a40a8d0473663f5ac32ecd4365bea097e47070b38803cbfae2b7a402233",
time: 1618587354,
tree: "01d0d36f8845f9ffad4f0a8812fbc5c4c69b45733199d7183307cb1a7d00353c0900100000017a8a6f641c487a313bb949623cca3b22b925adfef8216866aa090546bcf520000001bf48febcd2a10e51d420782990e17b746d5ce0f3292007e60a2eeb830bc46d0201ab6e0123bf72f70255ec4cacd33935b19ff834d481d67e06801073d0b8f0ea2a0121f42f607885a0158022413591af8eca7eae38b10c46e3ac81a9bfe70046e51d018229160dbe1f1d9e02d738e9d5060497e786e7434c80c32db7b8c96878e9904601034e6b1c73f09aa81f16a13cdb2188a53d8761483470f0bea01bfb84eb2cea1100018469338dcbdf2f7e54bca5bc3e1c5fad4a656f206040436d3d0433a901218b5e016d559de7a1a382349cf97fe01a2fba41a49bb5e3b306d9ff8c2bcc301c731c00000001f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1414969 ..< 1420000:
return WalletBirthday(
height: 1414969,
hash: "00212ba35169b77dba4eb4f5ce8c10da31a9df6dd61bb434f2f9e159d78913bd",
time: 1621459669,
tree: "01a9497fdb3add3bc2d0676f3163d94cda7c8cf8112d9dd8d2e7611b187c600a410010000143905c99f7bb45b164c636bb2443d9621db8147dba6a84a279fa8ed8f012083d00016847084e044e84059ea4b88b8af2de3f65c72adcee21522d5ee9d370d70f525b0000014d03c61befc68d02710784399567067db98f24eda340a1fd4a3ecc549d0fd0660001b4c1c846cae1423eaf52f1a8b1bfdde9ed9d43ced4d80dba9e72d862a0e03e4001ba0d7aa9e68417291c63b835fa64114f5899208238de59ee360f594c8b6c1b72018469338dcbdf2f7e54bca5bc3e1c5fad4a656f206040436d3d0433a901218b5e016d559de7a1a382349cf97fe01a2fba41a49bb5e3b306d9ff8c2bcc301c731c00000001f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1420000 ..< 1430000:
return WalletBirthday(
height: 1420000,
hash: "0089952e8ca00ee452412c3eef20403f9bc84751fc6ceb630c8a2eb149f051ca",
time: 1621783347,
tree: "0107478e9125e3050506cbeea850266d94108997ec3ef101d9693d136611b4076c00100001dfcde451d111cd50bac54c4ed4e238ca3dd8dcfcb8b50eabccb11a12dbcad71b0001cffd776a8fd6e5df911d000876525aa1d792a4f764e252dac9af69dd8ef3046d0106d4ec443aa1194ea579a1aa179bd5a29eeb4a5a01ccbfcf7af9cadc58225a6900014d03c61befc68d02710784399567067db98f24eda340a1fd4a3ecc549d0fd0660001b4c1c846cae1423eaf52f1a8b1bfdde9ed9d43ced4d80dba9e72d862a0e03e4001ba0d7aa9e68417291c63b835fa64114f5899208238de59ee360f594c8b6c1b72018469338dcbdf2f7e54bca5bc3e1c5fad4a656f206040436d3d0433a901218b5e016d559de7a1a382349cf97fe01a2fba41a49bb5e3b306d9ff8c2bcc301c731c00000001f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1430000 ..< 1440000:
return WalletBirthday(
height: 1430000,
hash: "01d9b2d83a7ec4ecede08df009e389b70535a5d41a1c6d1ce0906381d06006e0",
time: 1622484411,
tree: "010ea3d173a66acda751cb72a86bcc1eed2708b997ca8c7292febbd4c19b41665e001001f908af1ee7296100c06672f69834e5be2dc8b5325945270d562669bba91b825d01c4b42187eb99ab242226f6f2a48a00d4e5b3b4201c931afe9bccc86f3fbdd46501f39c0c0c1f725fa6b3ab8b58e60b280207a41199e2e218405f31ae18f0759f16000154daf736c7f68b0f22072be3e6b59434618b514c0c32d044c187048e2600c60b01f98b75b62bf721db663a442cbfa411242ec07ccb70aee42ea3618ca7b157270a014d03c61befc68d02710784399567067db98f24eda340a1fd4a3ecc549d0fd0660001b4c1c846cae1423eaf52f1a8b1bfdde9ed9d43ced4d80dba9e72d862a0e03e4001ba0d7aa9e68417291c63b835fa64114f5899208238de59ee360f594c8b6c1b72018469338dcbdf2f7e54bca5bc3e1c5fad4a656f206040436d3d0433a901218b5e016d559de7a1a382349cf97fe01a2fba41a49bb5e3b306d9ff8c2bcc301c731c00000001f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1440000 ..< 1450000:
return WalletBirthday(
height: 1440000,
hash: "0026a36cf31a5442caa1ac6d7be2773e1e58a3ccb6ae1116e84e6c90ddc95ec9",
time: 1623136353,
tree: "018d8cc853fd33af2a13ea00f379fe882fc56ecea3e0b1ecb75ac3b9783b443d3b01922d8ec71070cbe88eef0576738169965839e841d2fbc09c85f1d64f3528d4341001ee3dbc8987d7be81ccd8a5b502e9385c447f3f8c9c34085a1d11f7b41ceb625b010c1d1b1687fd081e55598e9bdcc5c565781ec867a12dd056384890f36fef434c00011674571f7aca05cc96139d2e59b08fe7a5b7b779da40a9903755b61e73421e64000001ccb87d20316142450d34c59bc515935f9adfd053a178ae8d799ea1f9bf02664901cc23dbfe7d27d7ad768868d7a96b6b31260ca34e4fbf164f652eb8e651f2fd3801b4c1c846cae1423eaf52f1a8b1bfdde9ed9d43ced4d80dba9e72d862a0e03e4001ba0d7aa9e68417291c63b835fa64114f5899208238de59ee360f594c8b6c1b72018469338dcbdf2f7e54bca5bc3e1c5fad4a656f206040436d3d0433a901218b5e016d559de7a1a382349cf97fe01a2fba41a49bb5e3b306d9ff8c2bcc301c731c00000001f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1450000 ..< 1460000:
return WalletBirthday(
height: 1450000,
hash: "000008a97bc133de13ca304e0c6a2a1b3f2facdceac2cde5b4141179f2a743cc",
time: 1623815069,
tree: "0175626cf9d8448de98f68fcc585dd7a276c946c11bbc3b192ee08db99c542b86b01acf5a110dc7ab911b534984c46bf56592f0c4cc8cf70dbd6a9cc4a5b47d2c81c1001c91f518ccb74093a217a640c537b69b095de058e0430046c8783f231caa1fa4201f7c982ce76b2c9343fb771e077357322f9a7dabfd7ab93b7adee32806c930d6600000170910ab6355ec614412fae56dad5fdc1747ce1b306a4b8ae03b77513b612b00800000000000000013d2fd009bf8a22d68f720eac19c411c99014ed9c5f85d5942e15d1fc039e28680001f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1460000 ..< 1470000:
return WalletBirthday(
height: 1460000,
hash: "00987b79a3c78d33dcb4d65e81a48b62a40c15d379a3983c4dffdd99a0c21d35",
time: 1624454126,
tree: "01f971b9781e857ab4acd5506174daf7ced473ad5a4a98134816d0c48de197d4400010000001ce49c67660eff9e404a3e4569ffa3ba98cc4514c05fa408beecd5c63420ef30e0192152273e4cbeafd426fa7df421310d2ccefad5e78f8d3e26dc283064b4d0d480188b70932b9ad821d4c9ecd57ed729a724723d22bdee4e5d4f08c9a924e68cf1501b2533ff180b8fb171fc0450fb7d1f91b7528bc19d88fdb2385c207b149d55e53017b499fdb9fe0db4bc418689d8f45f38b127b67d0445c421bfa6892c870610e260000000000013d2fd009bf8a22d68f720eac19c411c99014ed9c5f85d5942e15d1fc039e28680001f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1470000 ..< 1480000:
return WalletBirthday(
height: 1470000,
hash: "0027c8d818126cc8ab96efdcf877c1fb54fb373f41ca8f06e68b0b7b0e304ac7",
time: 1625121412,
tree: "012442af751714abfbb1f6b815b187eecbb60849e29dca1e3acccfbfd73f6bb8150010000109777ddd46c0a0e7eb91f31735f6078c54334f9a6d22d6421898bd44fd83ce140000013337975cc4704be21cbecce1c877936ce395128f6264fcb91ba8c028e7f25230015d7589dc1009350a87831e2fa9c4d9d3ca61754644f1a1d5d09499567fdcb11e0136e55cb009dd4f8bb8a3469b27ec325f06552a66bef2d898b6a72063107d03350001a7b951c79a184af5bda58c8be77db9b1e3813df0de344f26b27e3ad02c325b3b000000013d2fd009bf8a22d68f720eac19c411c99014ed9c5f85d5942e15d1fc039e28680001f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1480000 ..< 1490000:
return WalletBirthday(
height: 1480000,
hash: "0019c7d1a7d9d962de329db0785f35f56c514826702714f8738d14da87f4f20d",
time: 1625795173,
tree: "01a61918852f89d4d68aa82e1d93a7ddc4285ab2cf6a2ce92e79c4b9b498662014016d8109b64819882e5d35ee6730f54dda3a4ddc8232edc22226a367542c977a23100000016891e1f6b99afb29292bd3157f89eb2b8c1f74eed9cef56f4a802939d7392a1a0001f6f393a6ab5b0bc04a6d751bdbcd64a2740ff93aef7e1527dcd5de0511c4fb3001b938c3d7a93793fa04d51cce0369e789316a72f227436e02fc0c45fdd88def3700000001260f6e9fac0922f98d58afbcc3f391ac19d5d944081466929a33b99df19c0e6a0000013d2fd009bf8a22d68f720eac19c411c99014ed9c5f85d5942e15d1fc039e28680001f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1490000 ..< 1500000:
return WalletBirthday(
height: 1490000,
hash: "00263c9eab1b6b5e37143a442a8aad242fada58bb5fc8d6a5dc9f217c8c7425c",
time: 1626460494,
tree: "01448b047d9d4611f923ceb0c01a2fc743c7b4a54f7a00e92d666cbd0f39980f3100100000000001d917913fed08004cf1c74eeb918829cb80e576187e2f8e0c0e12a7e9849a9b400130282bcf71d57c40235baa4a3e045d89803c1fe069803da86ccebf25435dd270014aad72f0f5c3cd459d6d89a68657fbd299c84be0228c1a8a50d63ff2f2f74e0a000001260f6e9fac0922f98d58afbcc3f391ac19d5d944081466929a33b99df19c0e6a0000013d2fd009bf8a22d68f720eac19c411c99014ed9c5f85d5942e15d1fc039e28680001f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1500000 ..< 1507328:
return WalletBirthday(
height: 1500000,
hash: "00047a34c61409682f44640af9352023ad92f69b827d0f2b288f152ebea50f46",
time: 1627076501,
tree: "01172b95f271c6af8f68388f08c8ef970db8ec8d8d61204ecb7b2bb2c38262b92d0010016284585a6c85dadfef27ff33f1403926b4bb391de92e8be797e4280cc4ca2971000001a1ff388639379c0120782b3929bd8871af797be4b651f694aa961bad65a9c12400000001d806c98bda9653d5ae22757eed750871e16e0fb657f52c3d771a4411668e84330001260f6e9fac0922f98d58afbcc3f391ac19d5d944081466929a33b99df19c0e6a0000013d2fd009bf8a22d68f720eac19c411c99014ed9c5f85d5942e15d1fc039e28680001f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1500000 ..< 1507328:
return WalletBirthday(
height: 1500000,
hash: "00047a34c61409682f44640af9352023ad92f69b827d0f2b288f152ebea50f46",
time: 1627076501,
tree: "01172b95f271c6af8f68388f08c8ef970db8ec8d8d61204ecb7b2bb2c38262b92d0010016284585a6c85dadfef27ff33f1403926b4bb391de92e8be797e4280cc4ca2971000001a1ff388639379c0120782b3929bd8871af797be4b651f694aa961bad65a9c12400000001d806c98bda9653d5ae22757eed750871e16e0fb657f52c3d771a4411668e84330001260f6e9fac0922f98d58afbcc3f391ac19d5d944081466929a33b99df19c0e6a0000013d2fd009bf8a22d68f720eac19c411c99014ed9c5f85d5942e15d1fc039e28680001f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
case 1507328 ..< BlockHeight.max:
return WalletBirthday(
height: 1507328,
hash: "0026c9b20540e1bde6aaa8674a4083587a6e2555bcf8bb42680a8870b8da0070",
time: 1627566512,
tree: "01beb58cd0d4ac4e0f61888c7d77c7d73d260453b526bc61a830c158319f01b22301070135db53749d6640bdfc3c3e25d71dd65dcdc2c5828fd992eaee63546194051000000105884e2f6fbe3d0754fca27e20881b74ea687d33a0ea817844330a187d20465a0192f904a39694089c3befc610fd8e1236d5e7cb3b19d2e1d5fc4019af31fbc80201870a7fec351119b307e79c83bb627b343a87668e1d68e60625212e40deb33c3d000001d806c98bda9653d5ae22757eed750871e16e0fb657f52c3d771a4411668e84330001260f6e9fac0922f98d58afbcc3f391ac19d5d944081466929a33b99df19c0e6a0000013d2fd009bf8a22d68f720eac19c411c99014ed9c5f85d5942e15d1fc039e28680001f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
default:
return WalletBirthday(
height: 1507328,
hash: "0026c9b20540e1bde6aaa8674a4083587a6e2555bcf8bb42680a8870b8da0070",
time: 1627566512,
tree: "01beb58cd0d4ac4e0f61888c7d77c7d73d260453b526bc61a830c158319f01b22301070135db53749d6640bdfc3c3e25d71dd65dcdc2c5828fd992eaee63546194051000000105884e2f6fbe3d0754fca27e20881b74ea687d33a0ea817844330a187d20465a0192f904a39694089c3befc610fd8e1236d5e7cb3b19d2e1d5fc4019af31fbc80201870a7fec351119b307e79c83bb627b343a87668e1d68e60625212e40deb33c3d000001d806c98bda9653d5ae22757eed750871e16e0fb657f52c3d771a4411668e84330001260f6e9fac0922f98d58afbcc3f391ac19d5d944081466929a33b99df19c0e6a0000013d2fd009bf8a22d68f720eac19c411c99014ed9c5f85d5942e15d1fc039e28680001f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
)
}
}
}

View File

@ -0,0 +1,241 @@
//
// ZcashSDK.swift
// ZcashLightClientKit
//
// Created by Francisco Gindre on 7/22/21.
//
import Foundation
public protocol ZcashNetwork {
var networkType: NetworkType { get }
var constants: NetworkConstants.Type { get }
}
public enum NetworkType {
case mainnet
case testnet
var networkId: UInt32 {
switch self {
case .mainnet:
return 1
case .testnet:
return 0
}
}
}
extension NetworkType {
static func forChainName(_ chainame: String) -> NetworkType? {
switch chainame {
case "test":
return .testnet
case "main":
return .mainnet
default:
return nil
}
}
}
public class ZcashNetworkBuilder {
public static func network(for networkType: NetworkType) -> ZcashNetwork {
switch networkType {
case .mainnet:
return ZcashMainnet()
case .testnet:
return ZcashTestnet()
}
}
}
class ZcashTestnet: ZcashNetwork {
var networkType: NetworkType = .testnet
var constants: NetworkConstants.Type = ZcashSDKTestnetConstants.self
}
class ZcashMainnet: ZcashNetwork {
var networkType: NetworkType = .mainnet
var constants: NetworkConstants.Type = ZcashSDKMainnetConstants.self
}
/**
Constants of ZcashLightClientKit. this constants don't
*/
public class ZcashSDK {
/**
The number of zatoshi that equal 1 ZEC.
*/
public static var ZATOSHI_PER_ZEC: BlockHeight = 100_000_000
/**
The theoretical maximum number of blocks in a reorg, due to other bottlenecks in the protocol design.
*/
public static var MAX_REORG_SIZE = 100
/**
The amount of blocks ahead of the current height where new transactions are set to expire. This value is controlled
by the rust backend but it is helpful to know what it is set to and should be kept in sync.
*/
public static var EXPIRY_OFFSET = 20
//
// Defaults
//
/**
Default size of batches of blocks to request from the compact block service.
*/
public static var DEFAULT_BATCH_SIZE = 100
/**
Default amount of time, in in seconds, to poll for new blocks. Typically, this should be about half the average
block time.
*/
public static var DEFAULT_POLL_INTERVAL: TimeInterval = 20
/**
Default attempts at retrying.
*/
public static var DEFAULT_RETRIES: Int = 5
/**
The default maximum amount of time to wait during retry backoff intervals. Failed loops will never wait longer than
this before retyring.
*/
public static var DEFAULT_MAX_BACKOFF_INTERVAL: TimeInterval = 600
/**
Default number of blocks to rewind when a chain reorg is detected. This should be large enough to recover from the
reorg but smaller than the theoretical max reorg size of 100.
*/
public static var DEFAULT_REWIND_DISTANCE: Int = 10
/**
The number of blocks to allow before considering our data to be stale. This usually helps with what to do when
returning from the background and is exposed via the Synchronizer's isStale function.
*/
public static var DEFAULT_STALE_TOLERANCE: Int = 10
/**
Default Name for LibRustZcash data.db
*/
public static var DEFAULT_DATA_DB_NAME = "data.db"
/**
Default Name for Compact Block caches db
*/
public static var DEFAULT_CACHES_DB_NAME = "caches.db"
/**
Default name for pending transactions db
*/
public static var DEFAULT_PENDING_DB_NAME = "pending.db"
/**
File name for the sapling spend params
*/
public static var SPEND_PARAM_FILE_NAME = "sapling-spend.params"
/**
File name for the sapling output params
*/
public static var OUTPUT_PARAM_FILE_NAME = "sapling-output.params"
/**
The Url that is used by default in zcashd.
We'll want to make this externally configurable, rather than baking it into the SDK but
this will do for now, since we're using a cloudfront URL that already redirects.
*/
public static var CLOUD_PARAM_DIR_URL = "https://z.cash/downloads/"
}
public protocol NetworkConstants {
/**
The height of the first sapling block. When it comes to shielded transactions, we do not need to consider any blocks
prior to this height, at all.
*/
static var SAPLING_ACTIVATION_HEIGHT: BlockHeight { get }
/**
Default Name for LibRustZcash data.db
*/
static var DEFAULT_DATA_DB_NAME: String { get }
/**
Default Name for Compact Block caches db
*/
static var DEFAULT_CACHES_DB_NAME: String { get }
/**
Default name for pending transactions db
*/
static var DEFAULT_PENDING_DB_NAME: String { get }
static var DEFAULT_DB_NAME_PREFIX: String { get }
/**
fixed height where the SDK considers that the ZIP-321 was deployed. This is a workaround
for librustzcash not figuring out the tx fee from the tx itself.
*/
static var FEE_CHANGE_HEIGHT: BlockHeight { get }
static func defaultFee(for height: BlockHeight) -> Int64
}
public extension NetworkConstants {
static func defaultFee(for height: BlockHeight = BlockHeight.max) -> Int64 {
guard height >= FEE_CHANGE_HEIGHT else { return 10_000 }
return 1_000
}
}
public class ZcashSDKMainnetConstants: NetworkConstants {
private init() {}
/**
The height of the first sapling block. When it comes to shielded transactions, we do not need to consider any blocks
prior to this height, at all.
*/
public static var SAPLING_ACTIVATION_HEIGHT: BlockHeight = 419_200
/**
Default Name for LibRustZcash data.db
*/
public static var DEFAULT_DATA_DB_NAME = "data.db"
/**
Default Name for Compact Block caches db
*/
public static var DEFAULT_CACHES_DB_NAME = "caches.db"
/**
Default name for pending transactions db
*/
public static var DEFAULT_PENDING_DB_NAME = "pending.db"
public static var DEFAULT_DB_NAME_PREFIX = "ZcashSdk_mainnet_"
public static var FEE_CHANGE_HEIGHT: BlockHeight = 1_077_550
}
public class ZcashSDKTestnetConstants: NetworkConstants {
private init() {}
/**
The height of the first sapling block. When it comes to shielded transactions, we do not need to consider any blocks
prior to this height, at all.
*/
public static var SAPLING_ACTIVATION_HEIGHT: BlockHeight = 280_000
/**
Default Name for LibRustZcash data.db
*/
public static var DEFAULT_DATA_DB_NAME = "data.db"
/**
Default Name for Compact Block caches db
*/
public static var DEFAULT_CACHES_DB_NAME = "caches.db"
/**
Default name for pending transactions db
*/
public static var DEFAULT_PENDING_DB_NAME = "pending.db"
public static var DEFAULT_DB_NAME_PREFIX = "ZcashSdk_testnet_"
/**
Estimated height where wallets are supposed to change the fee
*/
public static var FEE_CHANGE_HEIGHT: BlockHeight = 1_028_500
}

View File

@ -57,13 +57,13 @@ public extension TransactionEntity {
return true return true
} }
var anchor: BlockHeight? { func anchor(network: ZcashNetwork) -> BlockHeight? {
if let minedHeight = self.minedHeight, minedHeight != -1 { if let minedHeight = self.minedHeight, minedHeight != -1 {
return max(minedHeight - ZcashSDK.DEFAULT_STALE_TOLERANCE, ZcashSDK.SAPLING_ACTIVATION_HEIGHT) return max(minedHeight - ZcashSDK.DEFAULT_STALE_TOLERANCE, network.constants.SAPLING_ACTIVATION_HEIGHT)
} }
if let expiryHeight = self.expiryHeight, expiryHeight != -1 { if let expiryHeight = self.expiryHeight, expiryHeight != -1 {
return max(expiryHeight - ZcashSDK.EXPIRY_OFFSET - ZcashSDK.DEFAULT_STALE_TOLERANCE, ZcashSDK.SAPLING_ACTIVATION_HEIGHT) return max(expiryHeight - ZcashSDK.EXPIRY_OFFSET - ZcashSDK.DEFAULT_STALE_TOLERANCE, network.constants.SAPLING_ACTIVATION_HEIGHT)
} }
return nil return nil

View File

@ -7,39 +7,6 @@
import Foundation import Foundation
/**
Ideally this extension shouldn't exist. Fees should be calculated from inputs and outputs. "Perfect is the enemy of good"
*/
public extension ZcashSDK {
/**
Returns the default fee at the time of that blockheight.
*/
static func defaultFee(for height: BlockHeight = BlockHeight.max) -> Int64 {
guard height >= feeChangeHeight else { return 10_000 }
return 1_000
}
/**
Estimated height where wallets are supposed to change the fee
*/
private static var feeChangeHeight: BlockHeight {
ZcashSDK.isMainnet ? 1_077_550 : 1_028_500
}
/**
minimum balance needed to do a shielding transaction
*/
static let shieldingThreshold: Int64 = 10000
enum NetworkType {
case mainnet
case testnet
}
}
public typealias ConsensusBranchID = Int32 public typealias ConsensusBranchID = Int32
public extension ConsensusBranchID { public extension ConsensusBranchID {
@ -53,12 +20,7 @@ public extension ConsensusBranchID {
} }
} }
extension ZcashSDK { extension NetworkType {
static var networkType: NetworkType {
self.isMainnet ? .mainnet : .testnet
}
}
extension ZcashSDK.NetworkType {
init?(_ string: String) { init?(_ string: String) {
switch string { switch string {
case "main": case "main":

View File

@ -75,6 +75,7 @@ public class Initializer {
private(set) var accountRepository: AccountRepository private(set) var accountRepository: AccountRepository
private(set) var storage: CompactBlockStorage private(set) var storage: CompactBlockStorage
private(set) var downloader: CompactBlockDownloader private(set) var downloader: CompactBlockDownloader
private(set) var network: ZcashNetwork
private(set) public var viewingKeys: [UnifiedViewingKey] private(set) public var viewingKeys: [UnifiedViewingKey]
private(set) public var walletBirthday: WalletBirthday private(set) public var walletBirthday: WalletBirthday
/** /**
@ -91,10 +92,11 @@ public class Initializer {
dataDbURL: URL, dataDbURL: URL,
pendingDbURL: URL, pendingDbURL: URL,
endpoint: LightWalletEndpoint, endpoint: LightWalletEndpoint,
network: ZcashNetwork,
spendParamsURL: URL, spendParamsURL: URL,
outputParamsURL: URL, outputParamsURL: URL,
viewingKeys: [UnifiedViewingKey], viewingKeys: [UnifiedViewingKey],
walletBirthday: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT, walletBirthday: BlockHeight,
alias: String = "", alias: String = "",
loggerProxy: Logger? = nil) { loggerProxy: Logger? = nil) {
@ -102,6 +104,7 @@ public class Initializer {
self.init(rustBackend: ZcashRustBackend.self, self.init(rustBackend: ZcashRustBackend.self,
lowerBoundHeight: walletBirthday, lowerBoundHeight: walletBirthday,
network: network,
cacheDbURL: cacheDbURL, cacheDbURL: cacheDbURL,
dataDbURL: dataDbURL, dataDbURL: dataDbURL,
pendingDbURL: pendingDbURL, pendingDbURL: pendingDbURL,
@ -124,6 +127,7 @@ public class Initializer {
*/ */
init(rustBackend: ZcashRustBackendWelding.Type, init(rustBackend: ZcashRustBackendWelding.Type,
lowerBoundHeight: BlockHeight, lowerBoundHeight: BlockHeight,
network: ZcashNetwork,
cacheDbURL: URL, cacheDbURL: URL,
dataDbURL: URL, dataDbURL: URL,
pendingDbURL: URL, pendingDbURL: URL,
@ -156,7 +160,8 @@ public class Initializer {
self.storage = storage self.storage = storage
self.downloader = CompactBlockDownloader(service: service, storage: storage) self.downloader = CompactBlockDownloader(service: service, storage: storage)
self.viewingKeys = viewingKeys self.viewingKeys = viewingKeys
self.walletBirthday = WalletBirthday.birthday(with: walletBirthday) self.walletBirthday = WalletBirthday.birthday(with: walletBirthday, network: network)
self.network = network
} }
/** /**
@ -182,7 +187,7 @@ public class Initializer {
} }
do { do {
try rustBackend.initDataDb(dbData: dataDbURL) try rustBackend.initDataDb(dbData: dataDbURL, networkType: network.networkType)
} catch RustWeldingError.dataDbNotEmpty { } catch RustWeldingError.dataDbNotEmpty {
// this is fine // this is fine
} catch { } catch {
@ -190,7 +195,7 @@ public class Initializer {
} }
do { do {
try rustBackend.initBlocksTable(dbData: dataDbURL, height: Int32(walletBirthday.height), hash: walletBirthday.hash, time: walletBirthday.time, saplingTree: walletBirthday.tree) try rustBackend.initBlocksTable(dbData: dataDbURL, height: Int32(walletBirthday.height), hash: walletBirthday.hash, time: walletBirthday.time, saplingTree: walletBirthday.tree, networkType: network.networkType)
} catch RustWeldingError.dataDbNotEmpty { } catch RustWeldingError.dataDbNotEmpty {
// this is fine // this is fine
} catch { } catch {
@ -202,7 +207,7 @@ public class Initializer {
lowerBoundHeight = max(walletBirthday.height, lastDownloaded) lowerBoundHeight = max(walletBirthday.height, lastDownloaded)
do { do {
guard try rustBackend.initAccountsTable(dbData: dataDbURL, uvks: viewingKeys) else { guard try rustBackend.initAccountsTable(dbData: dataDbURL, uvks: viewingKeys, networkType: network.networkType) else {
throw rustBackend.lastError() ?? InitializerError.accountInitFailed throw rustBackend.lastError() ?? InitializerError.accountInitFailed
} }
} catch RustWeldingError.dataDbNotEmpty { } catch RustWeldingError.dataDbNotEmpty {
@ -212,7 +217,9 @@ public class Initializer {
} }
let migrationManager = MigrationManager(cacheDbConnection: SimpleConnectionProvider(path: cacheDbURL.path), let migrationManager = MigrationManager(cacheDbConnection: SimpleConnectionProvider(path: cacheDbURL.path),
dataDbConnection: SimpleConnectionProvider(path: dataDbURL.path), pendingDbConnection: SimpleConnectionProvider(path: pendingDbURL.path)) dataDbConnection: SimpleConnectionProvider(path: dataDbURL.path),
pendingDbConnection: SimpleConnectionProvider(path: pendingDbURL.path),
networkType: self.network.networkType)
try migrationManager.performMigration(uvks: viewingKeys) try migrationManager.performMigration(uvks: viewingKeys)
} }
@ -229,7 +236,7 @@ public class Initializer {
- Parameter account: the index of the account - Parameter account: the index of the account
*/ */
public func getBalance(account index: Int = 0) -> Int64 { public func getBalance(account index: Int = 0) -> Int64 {
rustBackend.getBalance(dbData: dataDbURL, account: Int32(index)) rustBackend.getBalance(dbData: dataDbURL, account: Int32(index), networkType: network.networkType)
} }
/** /**
@ -237,20 +244,20 @@ public class Initializer {
- Parameter account: the index of the account - Parameter account: the index of the account
*/ */
public func getVerifiedBalance(account index: Int = 0) -> Int64 { public func getVerifiedBalance(account index: Int = 0) -> Int64 {
rustBackend.getVerifiedBalance(dbData: dataDbURL, account: Int32(index)) rustBackend.getVerifiedBalance(dbData: dataDbURL, account: Int32(index), networkType: network.networkType)
} }
/** /**
checks if the provided address is a valid shielded zAddress checks if the provided address is a valid shielded zAddress
*/ */
public func isValidShieldedAddress(_ address: String) -> Bool { public func isValidShieldedAddress(_ address: String) -> Bool {
(try? rustBackend.isValidShieldedAddress(address)) ?? false (try? rustBackend.isValidShieldedAddress(address, networkType: network.networkType)) ?? false
} }
/** /**
checks if the provided address is a transparent zAddress checks if the provided address is a transparent zAddress
*/ */
public func isValidTransparentAddress(_ address: String) -> Bool { public func isValidTransparentAddress(_ address: String) -> Bool {
(try? rustBackend.isValidTransparentAddress(address)) ?? false (try? rustBackend.isValidTransparentAddress(address,networkType: network.networkType)) ?? false
} }
func isSpendParameterPresent() -> Bool { func isSpendParameterPresent() -> Bool {

View File

@ -21,23 +21,28 @@ public protocol ResourceProvider {
Convenience provider for a data db and cache db resources. Convenience provider for a data db and cache db resources.
*/ */
public struct DefaultResourceProvider: ResourceProvider { public struct DefaultResourceProvider: ResourceProvider {
init(network: ZcashNetwork) {
self.network = network
}
var network: ZcashNetwork
public var dataDbURL: URL { public var dataDbURL: URL {
let constants = network.constants
do { do {
let url = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) let url = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
return url.appendingPathComponent(ZcashSDK.DEFAULT_DATA_DB_NAME) return url.appendingPathComponent(constants.DEFAULT_DATA_DB_NAME)
} catch { } catch {
return URL(fileURLWithPath: "file://\(ZcashSDK.DEFAULT_DATA_DB_NAME)") return URL(fileURLWithPath: "file://\(constants.DEFAULT_DATA_DB_NAME)")
} }
} }
public var cacheDbURL: URL { public var cacheDbURL: URL {
let constants = network.constants
do { do {
let path = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) let path = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
return path.appendingPathComponent(ZcashSDK.DEFAULT_CACHES_DB_NAME) return path.appendingPathComponent(constants.DEFAULT_CACHES_DB_NAME)
} catch { } catch {
return URL(fileURLWithPath: "file://\(ZcashSDK.DEFAULT_CACHES_DB_NAME)") return URL(fileURLWithPath: "file://\(constants.DEFAULT_CACHES_DB_NAME)")
} }
} }

View File

@ -36,9 +36,9 @@ class ZcashRustBackend: ZcashRustBackendWelding {
/** /**
* Sets up the internal structure of the data database. * Sets up the internal structure of the data database.
*/ */
static func initDataDb(dbData: URL) throws { static func initDataDb(dbData: URL, networkType: NetworkType) throws {
let dbData = dbData.osStr() let dbData = dbData.osStr()
guard zcashlc_init_data_database(dbData.0, dbData.1) != 0 else { guard zcashlc_init_data_database(dbData.0, dbData.1, networkType.networkId) != 0 else {
if let error = lastError() { if let error = lastError() {
throw throwDataDbError(error) throw throwDataDbError(error)
} }
@ -46,12 +46,12 @@ class ZcashRustBackend: ZcashRustBackendWelding {
} }
} }
static func isValidShieldedAddress(_ address: String) throws -> Bool { static func isValidShieldedAddress(_ address: String, networkType: NetworkType) throws -> Bool {
guard !address.containsCStringNullBytesBeforeStringEnding() else { guard !address.containsCStringNullBytesBeforeStringEnding() else {
return false return false
} }
guard zcashlc_is_valid_shielded_address([CChar](address.utf8CString)) else { guard zcashlc_is_valid_shielded_address([CChar](address.utf8CString), networkType.networkId) else {
if let error = lastError() { if let error = lastError() {
throw error throw error
} }
@ -60,12 +60,12 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return true return true
} }
static func isValidTransparentAddress(_ address: String) throws -> Bool { static func isValidTransparentAddress(_ address: String, networkType: NetworkType) throws -> Bool {
guard !address.containsCStringNullBytesBeforeStringEnding() else { guard !address.containsCStringNullBytesBeforeStringEnding() else {
return false return false
} }
guard zcashlc_is_valid_transparent_address([CChar](address.utf8CString)) else { guard zcashlc_is_valid_transparent_address([CChar](address.utf8CString), networkType.networkId ) else {
if let error = lastError() { if let error = lastError() {
throw error throw error
} }
@ -74,12 +74,12 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return true return true
} }
static func isValidExtendedFullViewingKey(_ key: String) throws -> Bool { static func isValidExtendedFullViewingKey(_ key: String, networkType: NetworkType) throws -> Bool {
guard !key.containsCStringNullBytesBeforeStringEnding() else { guard !key.containsCStringNullBytesBeforeStringEnding() else {
return false return false
} }
guard zcashlc_is_valid_viewing_key([CChar](key.utf8CString)) else { guard zcashlc_is_valid_viewing_key([CChar](key.utf8CString), networkType.networkId) else {
if let error = lastError() { if let error = lastError() {
throw error throw error
} }
@ -88,10 +88,10 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return true return true
} }
static func initAccountsTable(dbData: URL, seed: [UInt8], accounts: Int32) -> [String]? { static func initAccountsTable(dbData: URL, seed: [UInt8], accounts: Int32, networkType: NetworkType) -> [String]? {
let dbData = dbData.osStr() let dbData = dbData.osStr()
var capacity = UInt(0); var capacity = UInt(0);
let extsksCStr = zcashlc_init_accounts_table(dbData.0, dbData.1, seed, UInt(seed.count), accounts, &capacity) let extsksCStr = zcashlc_init_accounts_table(dbData.0, dbData.1, seed, UInt(seed.count), accounts, &capacity, networkType.networkId)
if extsksCStr == nil { if extsksCStr == nil {
return nil return nil
} }
@ -104,7 +104,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return extsks return extsks
} }
static func initAccountsTable(dbData: URL, uvks: [UnifiedViewingKey]) throws -> Bool { static func initAccountsTable(dbData: URL, uvks: [UnifiedViewingKey], networkType: NetworkType) throws -> Bool {
let dbData = dbData.osStr() let dbData = dbData.osStr()
var ffiUvks = [FFIUnifiedViewingKey]() var ffiUvks = [FFIUnifiedViewingKey]()
@ -115,6 +115,10 @@ class ZcashRustBackend: ZcashRustBackendWelding {
guard !uvk.extpub.containsCStringNullBytesBeforeStringEnding() else { guard !uvk.extpub.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput throw RustWeldingError.malformedStringInput
} }
guard try self.isValidExtendedFullViewingKey(uvk.extfvk, networkType: networkType) else {
throw RustWeldingError.malformedStringInput
}
let extfvkCStr = [CChar](String(uvk.extfvk).utf8CString) let extfvkCStr = [CChar](String(uvk.extfvk).utf8CString)
@ -133,7 +137,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
let slice = UnsafeMutablePointer<FFIUVKBoxedSlice>.allocate(capacity: 1) let slice = UnsafeMutablePointer<FFIUVKBoxedSlice>.allocate(capacity: 1)
slice.initialize(to: FFIUVKBoxedSlice(ptr: p.baseAddress, len: UInt(p.count))) slice.initialize(to: FFIUVKBoxedSlice(ptr: p.baseAddress, len: UInt(p.count)))
result = zcashlc_init_accounts_table_with_keys(dbData.0, dbData.1, slice) result = zcashlc_init_accounts_table_with_keys(dbData.0, dbData.1, slice, networkType.networkId)
slice.deinitialize(count: 1) slice.deinitialize(count: 1)
} }
@ -147,29 +151,8 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return result return result
} }
// static func initAccountsTable(dbData: URL, exfvks: [String]) throws -> Bool {
// let dbData = dbData.osStr()
// let viewingKeys = exfvks.map { UnsafePointer(strdup($0)) }
//
// guard exfvks.count > 0 else {
// throw RustWeldingError.malformedStringInput
// }
//
// let res = zcashlc_init_accounts_table_with_keys(dbData.0, dbData.1, viewingKeys, UInt(viewingKeys.count));
//
// viewingKeys.compactMap({ UnsafeMutablePointer(mutating: $0) }).forEach({ free($0) })
//
// guard res else {
// if let error = lastError() {
// throw error
// }
// return false
// }
// return res
//
// }
static func initBlocksTable(dbData: URL, height: Int32, hash: String, time: UInt32, saplingTree: String) throws { static func initBlocksTable(dbData: URL, height: Int32, hash: String, time: UInt32, saplingTree: String, networkType: NetworkType) throws {
let dbData = dbData.osStr() let dbData = dbData.osStr()
guard !hash.containsCStringNullBytesBeforeStringEnding() else { guard !hash.containsCStringNullBytesBeforeStringEnding() else {
@ -180,7 +163,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
throw RustWeldingError.malformedStringInput throw RustWeldingError.malformedStringInput
} }
guard zcashlc_init_blocks_table(dbData.0, dbData.1, height, [CChar](hash.utf8CString), time, [CChar](saplingTree.utf8CString)) != 0 else { guard zcashlc_init_blocks_table(dbData.0, dbData.1, height, [CChar](hash.utf8CString), time, [CChar](saplingTree.utf8CString), networkType.networkId) != 0 else {
if let error = lastError() { if let error = lastError() {
throw error throw error
} }
@ -188,52 +171,65 @@ class ZcashRustBackend: ZcashRustBackendWelding {
} }
} }
static func getAddress(dbData: URL, account: Int32) -> String? { static func getAddress(dbData: URL, account: Int32, networkType: NetworkType) -> String? {
let dbData = dbData.osStr() let dbData = dbData.osStr()
guard let addressCStr = zcashlc_get_address(dbData.0, dbData.1, account) else { return nil } guard let addressCStr = zcashlc_get_address(dbData.0, dbData.1, account, networkType.networkId) else { return nil }
let address = String(validatingUTF8: addressCStr) let address = String(validatingUTF8: addressCStr)
zcashlc_string_free(addressCStr) zcashlc_string_free(addressCStr)
return address return address
} }
static func getBalance(dbData: URL, account: Int32) -> Int64 { static func getBalance(dbData: URL, account: Int32, networkType: NetworkType) -> Int64 {
let dbData = dbData.osStr() let dbData = dbData.osStr()
return zcashlc_get_balance(dbData.0, dbData.1, account) return zcashlc_get_balance(dbData.0, dbData.1, account, networkType.networkId)
} }
static func getVerifiedBalance(dbData: URL, account: Int32) -> Int64 { static func getVerifiedBalance(dbData: URL, account: Int32, networkType: NetworkType) -> Int64 {
let dbData = dbData.osStr() let dbData = dbData.osStr()
return zcashlc_get_verified_balance(dbData.0, dbData.1, account) return zcashlc_get_verified_balance(dbData.0, dbData.1, account, networkType.networkId)
} }
static func getVerifiedTransparentBalance(dbData: URL, address: String) throws -> Int64 { static func getVerifiedTransparentBalance(dbData: URL, address: String, networkType: NetworkType) throws -> Int64 {
guard !address.containsCStringNullBytesBeforeStringEnding() else { guard !address.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput throw RustWeldingError.malformedStringInput
} }
guard try isValidTransparentAddress(address, networkType: networkType) else {
throw RustWeldingError.unableToDeriveKeys
}
let dbData = dbData.osStr() let dbData = dbData.osStr()
return zcashlc_get_verified_transparent_balance(dbData.0, dbData.1, [CChar](address.utf8CString)) return zcashlc_get_verified_transparent_balance(dbData.0, dbData.1, [CChar](address.utf8CString), networkType.networkId)
} }
static func getTransparentBalance(dbData: URL, address: String) throws -> Int64 { static func getTransparentBalance(dbData: URL, address: String, networkType: NetworkType) throws -> Int64 {
guard !address.containsCStringNullBytesBeforeStringEnding() else { guard !address.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput throw RustWeldingError.malformedStringInput
} }
guard try self.isValidTransparentAddress(address, networkType: networkType) else {
throw RustWeldingError.unableToDeriveKeys
}
let dbData = dbData.osStr() let dbData = dbData.osStr()
return zcashlc_get_total_transparent_balance(dbData.0, dbData.1, [CChar](address.utf8CString)) return zcashlc_get_total_transparent_balance(dbData.0, dbData.1, [CChar](address.utf8CString), networkType.networkId)
} }
static func clearUtxos(dbData: URL, address: String, sinceHeight: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT) throws -> Int32 {
static func clearUtxos(dbData: URL, address: String, sinceHeight: BlockHeight, networkType: NetworkType) throws -> Int32 {
let dbData = dbData.osStr() let dbData = dbData.osStr()
guard !address.containsCStringNullBytesBeforeStringEnding() else { guard !address.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput throw RustWeldingError.malformedStringInput
} }
let result = zcashlc_clear_utxos(dbData.0, dbData.1, [CChar](address.utf8CString), Int32(sinceHeight)) guard try isValidTransparentAddress(address, networkType: networkType) else {
throw RustWeldingError.unableToDeriveKeys
}
let result = zcashlc_clear_utxos(dbData.0, dbData.1, [CChar](address.utf8CString), Int32(sinceHeight), networkType.networkId)
guard result > 0 else { guard result > 0 else {
if let error = lastError() { if let error = lastError() {
@ -244,7 +240,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return result return result
} }
static func putUnspentTransparentOutput(dbData: URL, address: String, txid: [UInt8], index: Int, script: [UInt8], value: Int64, height: BlockHeight) throws -> Bool { static func putUnspentTransparentOutput(dbData: URL, address: String, txid: [UInt8], index: Int, script: [UInt8], value: Int64, height: BlockHeight, networkType: NetworkType) throws -> Bool {
let dbData = dbData.osStr() let dbData = dbData.osStr()
@ -261,7 +257,8 @@ class ZcashRustBackend: ZcashRustBackendWelding {
script, script,
UInt(script.count), UInt(script.count),
value, value,
Int32(height)) else { Int32(height),
networkType.networkId) else {
if let error = lastError() { if let error = lastError() {
throw error throw error
} }
@ -270,60 +267,61 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return true return true
} }
static func downloadedUtxoBalance(dbData: URL, address: String) throws -> WalletBalance { static func downloadedUtxoBalance(dbData: URL, address: String, networkType: NetworkType) throws -> WalletBalance {
let verified = try getVerifiedTransparentBalance(dbData: dbData, address: address) let verified = try getVerifiedTransparentBalance(dbData: dbData, address: address, networkType: networkType)
let total = try getTransparentBalance(dbData: dbData, address: address) let total = try getTransparentBalance(dbData: dbData, address: address, networkType: networkType)
return TransparentBalance(verified: verified, total: total, address: address) return TransparentBalance(verified: verified, total: total, address: address)
} }
static func getReceivedMemoAsUTF8(dbData: URL, idNote: Int64) -> String? { static func getReceivedMemoAsUTF8(dbData: URL, idNote: Int64, networkType: NetworkType) -> String? {
let dbData = dbData.osStr() let dbData = dbData.osStr()
guard let memoCStr = zcashlc_get_received_memo_as_utf8(dbData.0, dbData.1, idNote) else { return nil } guard let memoCStr = zcashlc_get_received_memo_as_utf8(dbData.0, dbData.1, idNote, networkType.networkId) else { return nil }
let memo = String(validatingUTF8: memoCStr) let memo = String(validatingUTF8: memoCStr)
zcashlc_string_free(memoCStr) zcashlc_string_free(memoCStr)
return memo return memo
} }
static func getSentMemoAsUTF8(dbData: URL, idNote: Int64) -> String? { static func getSentMemoAsUTF8(dbData: URL, idNote: Int64, networkType: NetworkType) -> String? {
let dbData = dbData.osStr() let dbData = dbData.osStr()
guard let memoCStr = zcashlc_get_sent_memo_as_utf8(dbData.0, dbData.1, idNote) else { return nil } guard let memoCStr = zcashlc_get_sent_memo_as_utf8(dbData.0, dbData.1, idNote, networkType.networkId) else { return nil }
let memo = String(validatingUTF8: memoCStr) let memo = String(validatingUTF8: memoCStr)
zcashlc_string_free(memoCStr) zcashlc_string_free(memoCStr)
return memo return memo
} }
static func validateCombinedChain(dbCache: URL, dbData: URL) -> Int32 { static func validateCombinedChain(dbCache: URL, dbData: URL, networkType: NetworkType) -> Int32 {
let dbCache = dbCache.osStr() let dbCache = dbCache.osStr()
let dbData = dbData.osStr() let dbData = dbData.osStr()
return zcashlc_validate_combined_chain(dbCache.0, dbCache.1, dbData.0, dbData.1) return zcashlc_validate_combined_chain(dbCache.0, dbCache.1, dbData.0, dbData.1, networkType.networkId)
} }
static func getNearestRewindHeight(dbData: URL, height: Int32) -> Int32 { static func getNearestRewindHeight(dbData: URL, height: Int32, networkType: NetworkType) -> Int32 {
let dbData = dbData.osStr() let dbData = dbData.osStr()
return zcashlc_get_nearest_rewind_height(dbData.0, dbData.1, height) return zcashlc_get_nearest_rewind_height(dbData.0, dbData.1, height, networkType.networkId)
} }
static func rewindToHeight(dbData: URL, height: Int32) -> Bool { static func rewindToHeight(dbData: URL, height: Int32, networkType: NetworkType) -> Bool {
let dbData = dbData.osStr() let dbData = dbData.osStr()
return zcashlc_rewind_to_height(dbData.0, dbData.1, height) return zcashlc_rewind_to_height(dbData.0, dbData.1, height, networkType.networkId)
} }
static func scanBlocks(dbCache: URL, dbData: URL, limit: UInt32 = 0) -> Bool { static func scanBlocks(dbCache: URL, dbData: URL, limit: UInt32 = 0, networkType: NetworkType) -> Bool {
let dbCache = dbCache.osStr() let dbCache = dbCache.osStr()
let dbData = dbData.osStr() let dbData = dbData.osStr()
return zcashlc_scan_blocks(dbCache.0, dbCache.1, dbData.0, dbData.1, limit) != 0 return zcashlc_scan_blocks(dbCache.0, dbCache.1, dbData.0, dbData.1, limit, networkType.networkId) != 0
} }
static func decryptAndStoreTransaction(dbData: URL, tx: [UInt8]) -> Bool { static func decryptAndStoreTransaction(dbData: URL, tx: [UInt8], networkType: NetworkType) -> Bool {
let dbData = dbData.osStr() let dbData = dbData.osStr()
return zcashlc_decrypt_and_store_transaction(dbData.0, dbData.1, tx, UInt(tx.count)) != 0 return zcashlc_decrypt_and_store_transaction(dbData.0, dbData.1, tx, UInt(tx.count), networkType.networkId) != 0
} }
static func createToAddress(dbData: URL, account: Int32, extsk: String, to: String, value: Int64, memo: String?, spendParamsPath: String, outputParamsPath: String) -> Int64 { static func createToAddress(dbData: URL, account: Int32, extsk: String, to: String, value: Int64, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64 {
let dbData = dbData.osStr() let dbData = dbData.osStr()
let memoBytes = memo ?? "" let memoBytes = memo ?? ""
@ -337,10 +335,11 @@ class ZcashRustBackend: ZcashRustBackendWelding {
spendParamsPath, spendParamsPath,
UInt(spendParamsPath.lengthOfBytes(using: .utf8)), UInt(spendParamsPath.lengthOfBytes(using: .utf8)),
outputParamsPath, outputParamsPath,
UInt(outputParamsPath.lengthOfBytes(using: .utf8))) UInt(outputParamsPath.lengthOfBytes(using: .utf8)),
networkType.networkId)
} }
static func shieldFunds(dbCache: URL, dbData: URL, account: Int32, tsk: String, extsk: String, memo: String?, spendParamsPath: String, outputParamsPath: String) -> Int64 { static func shieldFunds(dbCache: URL, dbData: URL, account: Int32, tsk: String, extsk: String, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64 {
let dbData = dbData.osStr() let dbData = dbData.osStr()
let memoBytes = memo ?? "" let memoBytes = memo ?? ""
@ -353,16 +352,18 @@ class ZcashRustBackend: ZcashRustBackendWelding {
spendParamsPath, spendParamsPath,
UInt(spendParamsPath.lengthOfBytes(using: .utf8)), UInt(spendParamsPath.lengthOfBytes(using: .utf8)),
outputParamsPath, outputParamsPath,
UInt(outputParamsPath.lengthOfBytes(using: .utf8))) UInt(outputParamsPath.lengthOfBytes(using: .utf8)),
networkType.networkId)
} }
static func deriveExtendedFullViewingKey(_ spendingKey: String) throws -> String? { static func deriveExtendedFullViewingKey(_ spendingKey: String, networkType: NetworkType) throws -> String? {
guard !spendingKey.containsCStringNullBytesBeforeStringEnding() else { guard !spendingKey.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput throw RustWeldingError.malformedStringInput
} }
guard let extsk = zcashlc_derive_extended_full_viewing_key([CChar](spendingKey.utf8CString)) else { guard let extsk = zcashlc_derive_extended_full_viewing_key([CChar](spendingKey.utf8CString),
networkType.networkId) else {
if let error = lastError() { if let error = lastError() {
throw error throw error
} }
@ -375,9 +376,9 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return derived return derived
} }
static func deriveExtendedFullViewingKeys(seed: [UInt8], accounts: Int32) throws -> [String]? { static func deriveExtendedFullViewingKeys(seed: [UInt8], accounts: Int32, networkType: NetworkType) throws -> [String]? {
var capacity = UInt(0); var capacity = UInt(0);
guard let extsksCStr = zcashlc_derive_extended_full_viewing_keys(seed, UInt(seed.count), accounts, &capacity) else { guard let extsksCStr = zcashlc_derive_extended_full_viewing_keys(seed, UInt(seed.count), accounts, &capacity, networkType.networkId) else {
if let error = lastError() { if let error = lastError() {
throw error throw error
} }
@ -392,9 +393,9 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return extsks return extsks
} }
static func deriveExtendedSpendingKeys(seed: [UInt8], accounts: Int32) throws -> [String]? { static func deriveExtendedSpendingKeys(seed: [UInt8], accounts: Int32, networkType: NetworkType) throws -> [String]? {
var capacity = UInt(0); var capacity = UInt(0);
guard let extsksCStr = zcashlc_derive_extended_spending_keys(seed, UInt(seed.count), accounts, &capacity) else { guard let extsksCStr = zcashlc_derive_extended_spending_keys(seed, UInt(seed.count), accounts, &capacity, networkType.networkId) else {
if let error = lastError() { if let error = lastError() {
throw error throw error
} }
@ -409,9 +410,9 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return extsks return extsks
} }
static func deriveUnifiedViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int) throws -> [UnifiedViewingKey] { static func deriveUnifiedViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int, networkType: NetworkType) throws -> [UnifiedViewingKey] {
guard let uvks_struct = zcashlc_derive_unified_viewing_keys_from_seed(seed, UInt(seed.count), Int32(numberOfAccounts)) else { guard let uvks_struct = zcashlc_derive_unified_viewing_keys_from_seed(seed, UInt(seed.count), Int32(numberOfAccounts), networkType.networkId) else {
if let error = lastError() { if let error = lastError() {
throw error throw error
} }
@ -443,8 +444,8 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return uvks return uvks
} }
static func deriveShieldedAddressFromSeed(seed: [UInt8], accountIndex: Int32) throws -> String? { static func deriveShieldedAddressFromSeed(seed: [UInt8], accountIndex: Int32, networkType: NetworkType) throws -> String? {
guard let zaddrCStr = zcashlc_derive_shielded_address_from_seed(seed, UInt(seed.count), accountIndex) else { guard let zaddrCStr = zcashlc_derive_shielded_address_from_seed(seed, UInt(seed.count), accountIndex, networkType.networkId) else {
if let error = lastError() { if let error = lastError() {
throw error throw error
} }
@ -457,12 +458,12 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return zAddr return zAddr
} }
static func deriveShieldedAddressFromViewingKey(_ extfvk: String) throws -> String? { static func deriveShieldedAddressFromViewingKey(_ extfvk: String, networkType: NetworkType) throws -> String? {
guard !extfvk.containsCStringNullBytesBeforeStringEnding() else { guard !extfvk.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput throw RustWeldingError.malformedStringInput
} }
guard let zaddrCStr = zcashlc_derive_shielded_address_from_viewing_key([CChar](extfvk.utf8CString)) else { guard let zaddrCStr = zcashlc_derive_shielded_address_from_viewing_key([CChar](extfvk.utf8CString), networkType.networkId) else {
if let error = lastError() { if let error = lastError() {
throw error throw error
} }
@ -475,9 +476,9 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return zAddr return zAddr
} }
static func deriveTransparentAddressFromSeed(seed: [UInt8], account: Int, index: Int) throws -> String? { static func deriveTransparentAddressFromSeed(seed: [UInt8], account: Int, index: Int, networkType: NetworkType) throws -> String? {
guard let tAddrCStr = zcashlc_derive_transparent_address_from_seed(seed, UInt(seed.count), Int32(account), Int32(index)) else { guard let tAddrCStr = zcashlc_derive_transparent_address_from_seed(seed, UInt(seed.count), Int32(account), Int32(index), networkType.networkId) else {
if let error = lastError() { if let error = lastError() {
throw error throw error
} }
@ -489,8 +490,8 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return tAddr return tAddr
} }
static func deriveTransparentPrivateKeyFromSeed(seed: [UInt8], account: Int, index: Int) throws -> String? { static func deriveTransparentPrivateKeyFromSeed(seed: [UInt8], account: Int, index: Int, networkType: NetworkType) throws -> String? {
guard let skCStr = zcashlc_derive_transparent_private_key_from_seed(seed, UInt(seed.count), Int32(account), Int32(index)) else { guard let skCStr = zcashlc_derive_transparent_private_key_from_seed(seed, UInt(seed.count), Int32(account), Int32(index), networkType.networkId) else {
if let error = lastError() { if let error = lastError() {
throw error throw error
} }
@ -501,12 +502,12 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return sk return sk
} }
static func derivedTransparentAddressFromPublicKey(_ pubkey: String) throws -> String { static func derivedTransparentAddressFromPublicKey(_ pubkey: String, networkType: NetworkType) throws -> String {
guard !pubkey.containsCStringNullBytesBeforeStringEnding() else { guard !pubkey.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput throw RustWeldingError.malformedStringInput
} }
guard let tAddrCStr = zcashlc_derive_transparent_address_from_public_key([CChar](pubkey.utf8CString)), let tAddr = String(validatingUTF8: tAddrCStr) else { guard let tAddrCStr = zcashlc_derive_transparent_address_from_public_key([CChar](pubkey.utf8CString), networkType.networkId), let tAddr = String(validatingUTF8: tAddrCStr) else {
if let error = lastError() { if let error = lastError() {
throw error throw error
} }
@ -515,12 +516,12 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return tAddr return tAddr
} }
static func deriveTransparentAddressFromSecretKey(_ tsk: String) throws -> String? { static func deriveTransparentAddressFromSecretKey(_ tsk: String, networkType: NetworkType) throws -> String? {
guard !tsk.containsCStringNullBytesBeforeStringEnding() else { guard !tsk.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput throw RustWeldingError.malformedStringInput
} }
guard let tAddrCStr = zcashlc_derive_transparent_address_from_secret_key([CChar](tsk.utf8CString)) else { guard let tAddrCStr = zcashlc_derive_transparent_address_from_secret_key([CChar](tsk.utf8CString), networkType.networkId) else {
if let error = lastError() { if let error = lastError() {
throw error throw error
} }
@ -531,8 +532,8 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return tAddr return tAddr
} }
static func consensusBranchIdFor(height: Int32) throws -> Int32 { static func consensusBranchIdFor(height: Int32, networkType: NetworkType) throws -> Int32 {
let branchId = zcashlc_branch_id_for_height(height) let branchId = zcashlc_branch_id_for_height(height, networkType.networkId)
guard branchId != -1 else { guard branchId != -1 else {
throw RustWeldingError.noConsensusBranchId(height: height) throw RustWeldingError.noConsensusBranchId(height: height)

View File

@ -35,25 +35,25 @@ public protocol ZcashRustBackendWelding {
initializes the data db initializes the data db
- Parameter dbData: location of the data db sql file - Parameter dbData: location of the data db sql file
*/ */
static func initDataDb(dbData: URL) throws static func initDataDb(dbData: URL, networkType: NetworkType) throws
/** /**
- Returns: true when the address is valid and shielded. Returns false in any other case - Returns: true when the address is valid and shielded. Returns false in any other case
- Throws: Error when the provided address belongs to another network - Throws: Error when the provided address belongs to another network
*/ */
static func isValidShieldedAddress(_ address: String) throws -> Bool static func isValidShieldedAddress(_ address: String, networkType: NetworkType) throws -> Bool
/** /**
- Returns: true when the address is valid and transparent. false in any other case - Returns: true when the address is valid and transparent. false in any other case
- Throws: Error when the provided address belongs to another network - Throws: Error when the provided address belongs to another network
*/ */
static func isValidTransparentAddress(_ address: String) throws -> Bool static func isValidTransparentAddress(_ address: String, networkType: NetworkType) throws -> Bool
/** /**
- Returns: true when the address is valid and transparent. false in any other case - Returns: true when the address is valid and transparent. false in any other case
- Throws: Error when there's another problem not related to validity of the string in question - Throws: Error when there's another problem not related to validity of the string in question
*/ */
static func isValidExtendedFullViewingKey(_ key: String) throws -> Bool static func isValidExtendedFullViewingKey(_ key: String, networkType: NetworkType) throws -> Bool
/** /**
initialize the accounts table from a given seed and a number of accounts initialize the accounts table from a given seed and a number of accounts
@ -62,7 +62,7 @@ public protocol ZcashRustBackendWelding {
- seed: byte array of the zip32 seed - seed: byte array of the zip32 seed
- accounts: how many accounts you want to have - accounts: how many accounts you want to have
*/ */
static func initAccountsTable(dbData: URL, seed: [UInt8], accounts: Int32) -> [String]? static func initAccountsTable(dbData: URL, seed: [UInt8], accounts: Int32, networkType: NetworkType) -> [String]?
/** /**
initialize the accounts table from a set of unified viewing keys initialize the accounts table from a set of unified viewing keys
@ -70,7 +70,7 @@ public protocol ZcashRustBackendWelding {
- dbData: location of the data db - dbData: location of the data db
- uvks: an array of UnifiedViewingKeys - uvks: an array of UnifiedViewingKeys
*/ */
static func initAccountsTable(dbData: URL, uvks: [UnifiedViewingKey]) throws -> Bool static func initAccountsTable(dbData: URL, uvks: [UnifiedViewingKey], networkType: NetworkType) throws -> Bool
/** /**
initialize the blocks table from a given checkpoint (birthday) initialize the blocks table from a given checkpoint (birthday)
@ -81,7 +81,7 @@ public protocol ZcashRustBackendWelding {
- time: in milliseconds from reference - time: in milliseconds from reference
- saplingTree: hash of the sapling tree - saplingTree: hash of the sapling tree
*/ */
static func initBlocksTable(dbData: URL, height: Int32, hash: String, time: UInt32, saplingTree: String) throws static func initBlocksTable(dbData: URL, height: Int32, hash: String, time: UInt32, saplingTree: String, networkType: NetworkType) throws
/** /**
gets the address from data db from the given account gets the address from data db from the given account
@ -90,38 +90,38 @@ public protocol ZcashRustBackendWelding {
- account: index of the given account - account: index of the given account
- Returns: an optional string with the address if found - Returns: an optional string with the address if found
*/ */
static func getAddress(dbData: URL, account: Int32) -> String? static func getAddress(dbData: URL, account: Int32, networkType: NetworkType) -> String?
/** /**
get the (unverified) balance from the given account get the (unverified) balance from the given account
- Parameters: - Parameters:
- dbData: location of the data db - dbData: location of the data db
- account: index of the given account - account: index of the given account
*/ */
static func getBalance(dbData: URL, account: Int32) -> Int64 static func getBalance(dbData: URL, account: Int32, networkType: NetworkType) -> Int64
/** /**
get the verified balance from the given account get the verified balance from the given account
- Parameters: - Parameters:
- dbData: location of the data db - dbData: location of the data db
- account: index of the given account - account: index of the given account
*/ */
static func getVerifiedBalance(dbData: URL, account: Int32) -> Int64 static func getVerifiedBalance(dbData: URL, account: Int32, networkType: NetworkType) -> Int64
/** /**
Get the verified cached transparent balance for the given address Get the verified cached transparent balance for the given address
*/ */
static func getVerifiedTransparentBalance(dbData: URL, address: String) throws -> Int64 static func getVerifiedTransparentBalance(dbData: URL, address: String, networkType: NetworkType) throws -> Int64
/** /**
Get the verified cached transparent balance for the given address Get the verified cached transparent balance for the given address
*/ */
static func getTransparentBalance(dbData: URL, address: String) throws -> Int64 static func getTransparentBalance(dbData: URL, address: String, networkType: NetworkType) throws -> Int64
/** /**
get received memo from note get received memo from note
- Parameters: - Parameters:
- dbData: location of the data db file - dbData: location of the data db file
- idNote: note_id of note where the memo is located - idNote: note_id of note where the memo is located
*/ */
static func getReceivedMemoAsUTF8(dbData: URL, idNote: Int64) -> String? static func getReceivedMemoAsUTF8(dbData: URL, idNote: Int64, networkType: NetworkType) -> String?
/** /**
get sent memo from note get sent memo from note
@ -129,7 +129,7 @@ public protocol ZcashRustBackendWelding {
- dbData: location of the data db file - dbData: location of the data db file
- idNote: note_id of note where the memo is located - idNote: note_id of note where the memo is located
*/ */
static func getSentMemoAsUTF8(dbData: URL, idNote: Int64) -> String? static func getSentMemoAsUTF8(dbData: URL, idNote: Int64, networkType: NetworkType) -> String?
/** /**
Checks that the scanned blocks in the data database, when combined with the recent Checks that the scanned blocks in the data database, when combined with the recent
@ -145,7 +145,7 @@ public protocol ZcashRustBackendWelding {
* `0` if there was an error during validation unrelated to chain validity. * `0` if there was an error during validation unrelated to chain validity.
- Important: This function does not mutate either of the databases. - Important: This function does not mutate either of the databases.
*/ */
static func validateCombinedChain(dbCache: URL, dbData: URL) -> Int32 static func validateCombinedChain(dbCache: URL, dbData: URL, networkType: NetworkType) -> Int32
/** /**
Returns the nearest height where a rewind is possible. Currently prunning gets rid of sapling witnesses older Returns the nearest height where a rewind is possible. Currently prunning gets rid of sapling witnesses older
@ -155,14 +155,14 @@ public protocol ZcashRustBackendWelding {
- dbData: location of the data db file - dbData: location of the data db file
- height: height you would like to rewind to. - height: height you would like to rewind to.
*/ */
static func getNearestRewindHeight(dbData: URL, height: Int32) -> Int32 static func getNearestRewindHeight(dbData: URL, height: Int32, networkType: NetworkType) -> Int32
/** /**
rewinds the compact block storage to the given height. clears up all derived data as well rewinds the compact block storage to the given height. clears up all derived data as well
- Parameters: - Parameters:
- dbData: location of the data db file - dbData: location of the data db file
- height: height to rewind to. DON'T PASS ARBITRARY HEIGHT. Use getNearestRewindHeight when unsure - height: height to rewind to. DON'T PASS ARBITRARY HEIGHT. Use getNearestRewindHeight when unsure
*/ */
static func rewindToHeight(dbData: URL, height: Int32) -> Bool static func rewindToHeight(dbData: URL, height: Int32, networkType: NetworkType) -> Bool
/** /**
Scans new blocks added to the cache for any transactions received by the tracked Scans new blocks added to the cache for any transactions received by the tracked
@ -183,7 +183,7 @@ public protocol ZcashRustBackendWelding {
- limit: scan up to limit blocks. pass 0 to set no limit. - limit: scan up to limit blocks. pass 0 to set no limit.
returns false if fails to scan. returns false if fails to scan.
*/ */
static func scanBlocks(dbCache: URL, dbData: URL, limit: UInt32) -> Bool static func scanBlocks(dbCache: URL, dbData: URL, limit: UInt32, networkType: NetworkType) -> Bool
/** /**
puts a UTXO into the data db database puts a UTXO into the data db database
@ -196,7 +196,7 @@ public protocol ZcashRustBackendWelding {
- height: the mined height for the UTXO - height: the mined height for the UTXO
- Returns: true if the operation succeded or false otherwise - Returns: true if the operation succeded or false otherwise
*/ */
static func putUnspentTransparentOutput(dbData: URL, address: String, txid: [UInt8], index: Int, script: [UInt8], value: Int64, height: BlockHeight) throws -> Bool static func putUnspentTransparentOutput(dbData: URL, address: String, txid: [UInt8], index: Int, script: [UInt8], value: Int64, height: BlockHeight, networkType: NetworkType) throws -> Bool
/** /**
clears the cached utxos for the given address from the specified height on clears the cached utxos for the given address from the specified height on
@ -207,7 +207,7 @@ public protocol ZcashRustBackendWelding {
- Returns: the amount of UTXOs cleared or -1 on error - Returns: the amount of UTXOs cleared or -1 on error
*/ */
static func clearUtxos(dbData: URL, address: String, sinceHeight: BlockHeight) throws -> Int32 static func clearUtxos(dbData: URL, address: String, sinceHeight: BlockHeight, networkType: NetworkType) throws -> Int32
/** /**
Gets the balance of the previously downloaded UTXOs Gets the balance of the previously downloaded UTXOs
- Parameters: - Parameters:
@ -216,7 +216,7 @@ public protocol ZcashRustBackendWelding {
- Returns: the wallet balance containing verified and total balance. - Returns: the wallet balance containing verified and total balance.
- Throws: Rustwelding Error if something fails - Throws: Rustwelding Error if something fails
*/ */
static func downloadedUtxoBalance(dbData: URL, address: String) throws -> WalletBalance static func downloadedUtxoBalance(dbData: URL, address: String, networkType: NetworkType) throws -> WalletBalance
/** /**
Scans a transaction for any information that can be decrypted by the accounts in the Scans a transaction for any information that can be decrypted by the accounts in the
@ -227,7 +227,7 @@ public protocol ZcashRustBackendWelding {
- tx: the transaction to decrypt - tx: the transaction to decrypt
returns false if fails to decrypt. returns false if fails to decrypt.
*/ */
static func decryptAndStoreTransaction(dbData: URL, tx: [UInt8]) -> Bool static func decryptAndStoreTransaction(dbData: URL, tx: [UInt8], networkType: NetworkType) -> Bool
/** /**
Creates a transaction to the given address from the given account Creates a transaction to the given address from the given account
@ -241,7 +241,7 @@ public protocol ZcashRustBackendWelding {
- spendParamsPath: path escaped String for the filesystem locations where the spend parameters are located - spendParamsPath: path escaped String for the filesystem locations where the spend parameters are located
- outputParamsPath: path escaped String for the filesystem locations where the output parameters are located - outputParamsPath: path escaped String for the filesystem locations where the output parameters are located
*/ */
static func createToAddress(dbData: URL, account: Int32, extsk: String, to: String, value: Int64, memo: String?, spendParamsPath: String, outputParamsPath: String) -> Int64 static func createToAddress(dbData: URL, account: Int32, extsk: String, to: String, value: Int64, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64
/** /**
Creates a transaction to shield all found UTXOs in cache db. Creates a transaction to shield all found UTXOs in cache db.
@ -255,7 +255,7 @@ public protocol ZcashRustBackendWelding {
- spendParamsPath: path escaped String for the filesystem locations where the spend parameters are located - spendParamsPath: path escaped String for the filesystem locations where the spend parameters are located
- outputParamsPath: path escaped String for the filesystem locations where the output parameters are located - outputParamsPath: path escaped String for the filesystem locations where the output parameters are located
*/ */
static func shieldFunds(dbCache: URL, dbData: URL, account: Int32, tsk: String, extsk: String, memo: String?, spendParamsPath: String, outputParamsPath: String) -> Int64 static func shieldFunds(dbCache: URL, dbData: URL, account: Int32, tsk: String, extsk: String, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64
/** /**
Derives a full viewing key from a seed Derives a full viewing key from a seed
@ -263,7 +263,7 @@ public protocol ZcashRustBackendWelding {
- Returns: the derived key - Returns: the derived key
- Throws: RustBackendError if fatal error occurs - Throws: RustBackendError if fatal error occurs
*/ */
static func deriveExtendedFullViewingKey(_ spendingKey: String) throws -> String? static func deriveExtendedFullViewingKey(_ spendingKey: String, networkType: NetworkType) throws -> String?
/** /**
Derives a set of full viewing keys from a seed Derives a set of full viewing keys from a seed
@ -272,7 +272,7 @@ public protocol ZcashRustBackendWelding {
- Returns: an array containing the derived keys - Returns: an array containing the derived keys
- Throws: RustBackendError if fatal error occurs - Throws: RustBackendError if fatal error occurs
*/ */
static func deriveExtendedFullViewingKeys(seed: [UInt8], accounts: Int32) throws -> [String]? static func deriveExtendedFullViewingKeys(seed: [UInt8], accounts: Int32, networkType: NetworkType) throws -> [String]?
/** /**
Derives a set of full viewing keys from a seed Derives a set of full viewing keys from a seed
@ -281,7 +281,7 @@ public protocol ZcashRustBackendWelding {
- Returns: an array containing the spending keys - Returns: an array containing the spending keys
- Throws: RustBackendError if fatal error occurs - Throws: RustBackendError if fatal error occurs
*/ */
static func deriveExtendedSpendingKeys(seed: [UInt8], accounts: Int32) throws -> [String]? static func deriveExtendedSpendingKeys(seed: [UInt8], accounts: Int32, networkType: NetworkType) throws -> [String]?
/** /**
Derives a shielded address from a seed Derives a shielded address from a seed
@ -290,7 +290,7 @@ public protocol ZcashRustBackendWelding {
- Returns: an optional String containing the Shielded address - Returns: an optional String containing the Shielded address
- Throws: RustBackendError if fatal error occurs - Throws: RustBackendError if fatal error occurs
*/ */
static func deriveShieldedAddressFromSeed(seed: [UInt8], accountIndex: Int32) throws -> String? static func deriveShieldedAddressFromSeed(seed: [UInt8], accountIndex: Int32, networkType: NetworkType) throws -> String?
/** /**
Derives a shielded address from an Extended Full Viewing Key Derives a shielded address from an Extended Full Viewing Key
@ -298,7 +298,7 @@ public protocol ZcashRustBackendWelding {
- Returns: an optional String containing the Shielded address - Returns: an optional String containing the Shielded address
- Throws: RustBackendError if fatal error occurs - Throws: RustBackendError if fatal error occurs
*/ */
static func deriveShieldedAddressFromViewingKey(_ extfvk: String) throws -> String? static func deriveShieldedAddressFromViewingKey(_ extfvk: String, networkType: NetworkType) throws -> String?
/** /**
Derives a shielded address from an Extended Full Viewing Key Derives a shielded address from an Extended Full Viewing Key
@ -306,14 +306,14 @@ public protocol ZcashRustBackendWelding {
- Returns: an optional String containing the transparent address - Returns: an optional String containing the transparent address
- Throws: RustBackendError if fatal error occurs - Throws: RustBackendError if fatal error occurs
*/ */
static func deriveTransparentAddressFromSeed(seed: [UInt8], account: Int, index: Int) throws -> String? static func deriveTransparentAddressFromSeed(seed: [UInt8], account: Int, index: Int, networkType: NetworkType) throws -> String?
/** /**
Derives a transparent secret key from Seed Derives a transparent secret key from Seed
- Parameter seed: an array of bytes containing the seed - Parameter seed: an array of bytes containing the seed
- Returns: an optional String containing the transparent secret (private) key - Returns: an optional String containing the transparent secret (private) key
*/ */
static func deriveTransparentPrivateKeyFromSeed(seed: [UInt8], account: Int, index: Int) throws -> String? static func deriveTransparentPrivateKeyFromSeed(seed: [UInt8], account: Int, index: Int, networkType: NetworkType) throws -> String?
/** /**
Derives a transparent address from a secret key Derives a transparent address from a secret key
@ -321,18 +321,18 @@ public protocol ZcashRustBackendWelding {
- Returns: an optional String containing the transparent address. - Returns: an optional String containing the transparent address.
*/ */
static func deriveTransparentAddressFromSecretKey(_ tsk: String) throws -> String? static func deriveTransparentAddressFromSecretKey(_ tsk: String, networkType: NetworkType) throws -> String?
/** /**
Derives a tranparent address from a public key Derives a tranparent address from a public key
- Parameter pubkey: public key represented as a string - Parameter pubkey: public key represented as a string
*/ */
static func derivedTransparentAddressFromPublicKey(_ pubkey: String) throws -> String static func derivedTransparentAddressFromPublicKey(_ pubkey: String, networkType: NetworkType) throws -> String
static func deriveUnifiedViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int) throws -> [UnifiedViewingKey] static func deriveUnifiedViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int, networkType: NetworkType) throws -> [UnifiedViewingKey]
/** /**
Gets the consensus branch id for the given height Gets the consensus branch id for the given height
- Parameter height: the height you what to know the branch id for - Parameter height: the height you what to know the branch id for
*/ */
static func consensusBranchIdFor(height: Int32) throws -> Int32 static func consensusBranchIdFor(height: Int32, networkType: NetworkType) throws -> Int32
} }

View File

@ -336,7 +336,7 @@ extension LightWalletGRPCService: LightWalletService {
return height return height
} }
public func fetchUTXOs(for tAddress: String, height: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT) throws -> [UnspentTransactionOutputEntity] { public func fetchUTXOs(for tAddress: String, height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
let arg = GetAddressUtxosArg.with { (utxoArgs) in let arg = GetAddressUtxosArg.with { (utxoArgs) in
utxoArgs.addresses = [tAddress] utxoArgs.addresses = [tAddress]
utxoArgs.startHeight = UInt64(height) utxoArgs.startHeight = UInt64(height)
@ -358,7 +358,7 @@ extension LightWalletGRPCService: LightWalletService {
} }
} }
public func fetchUTXOs(for tAddress: String, height: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) { public func fetchUTXOs(for tAddress: String, height: BlockHeight, result: @escaping (Result<[UnspentTransactionOutputEntity], LightWalletServiceError>) -> Void) {
queue.async { [weak self] in queue.async { [weak self] in
guard let self = self else { return } guard let self = self else { return }
let arg = GetAddressUtxosArg.with { (utxoArgs) in let arg = GetAddressUtxosArg.with { (utxoArgs) in
@ -394,7 +394,7 @@ extension LightWalletGRPCService: LightWalletService {
} }
} }
public func fetchUTXOs(for tAddresses: [String], height: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT) throws -> [UnspentTransactionOutputEntity] { public func fetchUTXOs(for tAddresses: [String], height: BlockHeight) throws -> [UnspentTransactionOutputEntity] {
guard tAddresses.count > 0 else { guard tAddresses.count > 0 else {
return [] // FIXME: throw a real error return [] // FIXME: throw a real error

View File

@ -16,17 +16,11 @@ extension CompactBlockRange {
extension BlockID { extension BlockID {
static let saplingActivationHeight: UInt64 = UInt64(ZcashSDK.SAPLING_ACTIVATION_HEIGHT)
init(height: UInt64) { init(height: UInt64) {
self = BlockID() self = BlockID()
self.height = height self.height = height
} }
static var saplingActivation: BlockID {
BlockID(height: saplingActivationHeight)
}
init(height: BlockHeight) { init(height: BlockHeight) {
self.init(height: UInt64(height)) self.init(height: UInt64(height))
} }
@ -46,16 +40,6 @@ extension BlockRange {
} }
} }
static func sinceSaplingActivation(to height: UInt64? = nil) -> BlockRange {
var blockRange = BlockRange()
blockRange.start = BlockID.saplingActivation
if let height = height {
blockRange.end = BlockID.init(height: height)
}
return blockRange
}
var compactBlockRange: CompactBlockRange { var compactBlockRange: CompactBlockRange {
return Int(self.start.height) ... Int(self.end.height) return Int(self.start.height) ... Int(self.end.height)
} }

View File

@ -394,7 +394,6 @@ extension SyncStatus {
} }
} }
extension SyncStatus { extension SyncStatus {
init(_ blockProcessorProgress: CompactBlockProgress) { init(_ blockProcessorProgress: CompactBlockProgress) {
switch blockProcessorProgress { switch blockProcessorProgress {

View File

@ -107,7 +107,11 @@ public class DerivationTool: KeyDeriving {
var rustwelding: ZcashRustBackendWelding.Type = ZcashRustBackend.self var rustwelding: ZcashRustBackendWelding.Type = ZcashRustBackend.self
public static let `default` = DerivationTool() var networkType: NetworkType
public init(networkType: NetworkType) {
self.networkType = networkType
}
/** /**
Given a seed and a number of accounts, return the associated viewing keys. Given a seed and a number of accounts, return the associated viewing keys.
@ -123,7 +127,7 @@ public class DerivationTool: KeyDeriving {
} }
do { do {
guard let keys = try rustwelding.deriveExtendedFullViewingKeys(seed: seed, accounts: numberOfAccounts) else { guard let keys = try rustwelding.deriveExtendedFullViewingKeys(seed: seed, accounts: numberOfAccounts, networkType: networkType) else {
throw KeyDerivationErrors.unableToDerive throw KeyDerivationErrors.unableToDerive
} }
return keys return keys
@ -141,7 +145,7 @@ public class DerivationTool: KeyDeriving {
*/ */
public func deriveViewingKey(spendingKey: String) throws -> String { public func deriveViewingKey(spendingKey: String) throws -> String {
do { do {
guard let key = try rustwelding.deriveExtendedFullViewingKey(spendingKey) else { guard let key = try rustwelding.deriveExtendedFullViewingKey(spendingKey, networkType: networkType) else {
throw KeyDerivationErrors.unableToDerive throw KeyDerivationErrors.unableToDerive
} }
return key return key
@ -165,7 +169,7 @@ public class DerivationTool: KeyDeriving {
throw KeyDerivationErrors.invalidInput throw KeyDerivationErrors.invalidInput
} }
do { do {
guard let keys = try rustwelding.deriveExtendedSpendingKeys(seed: seed, accounts: numberOfAccounts) else { guard let keys = try rustwelding.deriveExtendedSpendingKeys(seed: seed, accounts: numberOfAccounts, networkType: networkType) else {
throw KeyDerivationErrors.unableToDerive throw KeyDerivationErrors.unableToDerive
} }
return keys return keys
@ -189,7 +193,7 @@ public class DerivationTool: KeyDeriving {
} }
do { do {
guard let address = try rustwelding.deriveShieldedAddressFromSeed(seed: seed, accountIndex: accountIndex) else { guard let address = try rustwelding.deriveShieldedAddressFromSeed(seed: seed, accountIndex: accountIndex, networkType: networkType) else {
throw KeyDerivationErrors.unableToDerive throw KeyDerivationErrors.unableToDerive
} }
return address return address
@ -209,7 +213,7 @@ public class DerivationTool: KeyDeriving {
*/ */
public func deriveShieldedAddress(viewingKey: String) throws -> String { public func deriveShieldedAddress(viewingKey: String) throws -> String {
do { do {
guard let zaddr = try rustwelding.deriveShieldedAddressFromViewingKey(viewingKey) else { guard let zaddr = try rustwelding.deriveShieldedAddressFromViewingKey(viewingKey, networkType: networkType) else {
throw KeyDerivationErrors.unableToDerive throw KeyDerivationErrors.unableToDerive
} }
return zaddr return zaddr
@ -220,7 +224,7 @@ public class DerivationTool: KeyDeriving {
public func deriveTransparentAddress(seed: [UInt8], account: Int = 0, index: Int = 0) throws -> String { public func deriveTransparentAddress(seed: [UInt8], account: Int = 0, index: Int = 0) throws -> String {
do { do {
guard let zaddr = try rustwelding.deriveTransparentAddressFromSeed(seed: seed, account: account, index: index) else { guard let zaddr = try rustwelding.deriveTransparentAddressFromSeed(seed: seed, account: account, index: index, networkType: networkType) else {
throw KeyDerivationErrors.unableToDerive throw KeyDerivationErrors.unableToDerive
} }
return zaddr return zaddr
@ -234,7 +238,7 @@ public class DerivationTool: KeyDeriving {
throw KeyDerivationErrors.invalidInput throw KeyDerivationErrors.invalidInput
} }
do { do {
return try rustwelding.deriveUnifiedViewingKeyFromSeed(seed, numberOfAccounts: numberOfAccounts) return try rustwelding.deriveUnifiedViewingKeyFromSeed(seed, numberOfAccounts: numberOfAccounts, networkType: networkType)
} catch { } catch {
throw KeyDerivationErrors.derivationError(underlyingError: error) throw KeyDerivationErrors.derivationError(underlyingError: error)
} }
@ -259,7 +263,7 @@ public class DerivationTool: KeyDeriving {
} }
do { do {
return try rustwelding.derivedTransparentAddressFromPublicKey(pubkey) return try rustwelding.derivedTransparentAddressFromPublicKey(pubkey, networkType: networkType)
} catch { } catch {
throw KeyDerivationErrors.derivationError(underlyingError: error) throw KeyDerivationErrors.derivationError(underlyingError: error)
} }
@ -273,7 +277,7 @@ public class DerivationTool: KeyDeriving {
*/ */
public func deriveTransparentPrivateKey(seed: [UInt8], account: Int = 0, index: Int = 0) throws -> String { public func deriveTransparentPrivateKey(seed: [UInt8], account: Int = 0, index: Int = 0) throws -> String {
do { do {
guard let sk = try rustwelding.deriveTransparentPrivateKeyFromSeed(seed: seed, account: account, index: index) else { guard let sk = try rustwelding.deriveTransparentPrivateKeyFromSeed(seed: seed, account: account, index: index, networkType: networkType) else {
throw KeyDerivationErrors.unableToDerive throw KeyDerivationErrors.unableToDerive
} }
return sk return sk
@ -288,7 +292,7 @@ extension DerivationTool: KeyValidation {
public func isValidExtendedViewingKey(_ extvk: String) throws -> Bool { public func isValidExtendedViewingKey(_ extvk: String) throws -> Bool {
do { do {
return try rustwelding.isValidExtendedFullViewingKey(extvk) return try rustwelding.isValidExtendedFullViewingKey(extvk, networkType: networkType)
} catch { } catch {
throw KeyDerivationErrors.derivationError(underlyingError: error) throw KeyDerivationErrors.derivationError(underlyingError: error)
} }
@ -296,7 +300,7 @@ extension DerivationTool: KeyValidation {
public func isValidTransparentAddress(_ tAddress: String) throws -> Bool { public func isValidTransparentAddress(_ tAddress: String) throws -> Bool {
do { do {
return try rustwelding.isValidTransparentAddress(tAddress) return try rustwelding.isValidTransparentAddress(tAddress, networkType: networkType)
} catch { } catch {
throw KeyDerivationErrors.derivationError(underlyingError: error) throw KeyDerivationErrors.derivationError(underlyingError: error)
} }
@ -304,7 +308,7 @@ extension DerivationTool: KeyValidation {
public func isValidShieldedAddress(_ zAddress: String) throws -> Bool { public func isValidShieldedAddress(_ zAddress: String) throws -> Bool {
do { do {
return try rustwelding.isValidShieldedAddress(zAddress) return try rustwelding.isValidShieldedAddress(zAddress, networkType: networkType)
} catch { } catch {
throw KeyDerivationErrors.derivationError(underlyingError: error) throw KeyDerivationErrors.derivationError(underlyingError: error)
} }
@ -318,7 +322,7 @@ extension DerivationTool: KeyValidation {
*/ */
public func deriveTransparentAddressFromPrivateKey(_ tsk: String) throws -> String { public func deriveTransparentAddressFromPrivateKey(_ tsk: String) throws -> String {
do { do {
guard let tAddr = try rustwelding.deriveTransparentAddressFromSecretKey(tsk) else { guard let tAddr = try rustwelding.deriveTransparentAddressFromSecretKey(tsk, networkType: networkType) else {
throw KeyDerivationErrors.unableToDerive throw KeyDerivationErrors.unableToDerive
} }
return tAddr return tAddr

View File

@ -24,10 +24,16 @@ class PersistentTransactionManager: OutboundTransactionManager {
var encoder: TransactionEncoder var encoder: TransactionEncoder
var service: LightWalletService var service: LightWalletService
var queue: DispatchQueue var queue: DispatchQueue
init(encoder: TransactionEncoder, service: LightWalletService, repository: PendingTransactionRepository) { var network: NetworkType
init(encoder: TransactionEncoder,
service: LightWalletService,
repository: PendingTransactionRepository,
networkType: NetworkType) {
self.repository = repository self.repository = repository
self.encoder = encoder self.encoder = encoder
self.service = service self.service = service
self.network = networkType
self.queue = DispatchQueue.init(label: "PersistentTransactionManager.serial.queue", qos: .userInitiated) self.queue = DispatchQueue.init(label: "PersistentTransactionManager.serial.queue", qos: .userInitiated)
} }
@ -44,7 +50,7 @@ class PersistentTransactionManager: OutboundTransactionManager {
queue.async { [weak self] in queue.async { [weak self] in
guard let self = self else { return } guard let self = self else { return }
let derivationTool = DerivationTool() let derivationTool = DerivationTool(networkType: self.network)
guard let vk = try? derivationTool.deriveViewingKey(spendingKey: spendingKey), guard let vk = try? derivationTool.deriveViewingKey(spendingKey: spendingKey),
let zAddr = try? derivationTool.deriveShieldedAddress(viewingKey: vk) else { let zAddr = try? derivationTool.deriveShieldedAddress(viewingKey: vk) else {
result(.failure(TransactionManagerError.shieldingEncodingFailed(tx: pendingTransaction, reason: "There was an error Deriving your keys"))) result(.failure(TransactionManagerError.shieldingEncodingFailed(tx: pendingTransaction, reason: "There was an error Deriving your keys")))
@ -243,7 +249,7 @@ class PersistentTransactionManager: OutboundTransactionManager {
class OutboundTransactionManagerBuilder { class OutboundTransactionManagerBuilder {
static func build(initializer: Initializer) throws -> OutboundTransactionManager { static func build(initializer: Initializer) throws -> OutboundTransactionManager {
return PersistentTransactionManager(encoder: TransactionEncoderbuilder.build(initializer: initializer), service: initializer.lightWalletService, repository: try PendingTransactionRepositoryBuilder.build(initializer: initializer)) return PersistentTransactionManager(encoder: TransactionEncoderbuilder.build(initializer: initializer), service: initializer.lightWalletService, repository: try PendingTransactionRepositoryBuilder.build(initializer: initializer), networkType: initializer.network.networkType)
} }
} }

View File

@ -16,13 +16,15 @@ class WalletTransactionEncoder: TransactionEncoder {
private var spendParamsURL: URL private var spendParamsURL: URL
private var dataDbURL: URL private var dataDbURL: URL
private var cacheDbURL: URL private var cacheDbURL: URL
private var networkType: NetworkType
init(rust: ZcashRustBackendWelding.Type, init(rust: ZcashRustBackendWelding.Type,
dataDb: URL, dataDb: URL,
cacheDb: URL, cacheDb: URL,
repository: TransactionRepository, repository: TransactionRepository,
outputParams: URL, outputParams: URL,
spendParams: URL) { spendParams: URL,
networkType: NetworkType) {
self.rustBackend = rust self.rustBackend = rust
self.dataDbURL = dataDb self.dataDbURL = dataDb
@ -30,6 +32,7 @@ class WalletTransactionEncoder: TransactionEncoder {
self.repository = repository self.repository = repository
self.outputParamsURL = outputParams self.outputParamsURL = outputParams
self.spendParamsURL = spendParams self.spendParamsURL = spendParams
self.networkType = networkType
self.queue = DispatchQueue(label: "wallet.transaction.encoder.serial.queue") self.queue = DispatchQueue(label: "wallet.transaction.encoder.serial.queue")
} }
@ -40,7 +43,8 @@ class WalletTransactionEncoder: TransactionEncoder {
cacheDb: initializer.cacheDbURL, cacheDb: initializer.cacheDbURL,
repository: initializer.transactionRepository, repository: initializer.transactionRepository,
outputParams: initializer.outputParamsURL, outputParams: initializer.outputParamsURL,
spendParams: initializer.spendParamsURL) spendParams: initializer.spendParamsURL,
networkType: initializer.network.networkType)
} }
@ -86,7 +90,8 @@ class WalletTransactionEncoder: TransactionEncoder {
value: Int64(zatoshi), value: Int64(zatoshi),
memo: memo, memo: memo,
spendParamsPath: self.spendParamsURL.path, spendParamsPath: self.spendParamsURL.path,
outputParamsPath: self.outputParamsURL.path) outputParamsPath: self.outputParamsURL.path,
networkType: networkType)
guard txId > 0 else { guard txId > 0 else {
throw rustBackend.lastError() ?? RustWeldingError.genericError(message: "create spend failed") throw rustBackend.lastError() ?? RustWeldingError.genericError(message: "create spend failed")
@ -130,7 +135,8 @@ class WalletTransactionEncoder: TransactionEncoder {
extsk: spendingKey, extsk: spendingKey,
memo: memo, memo: memo,
spendParamsPath: self.spendParamsURL.path, spendParamsPath: self.spendParamsURL.path,
outputParamsPath: self.outputParamsURL.path) outputParamsPath: self.outputParamsURL.path,
networkType: networkType)
guard txId > 0 else { guard txId > 0 else {
throw rustBackend.lastError() ?? RustWeldingError.genericError(message: "create spend failed") throw rustBackend.lastError() ?? RustWeldingError.genericError(message: "create spend failed")

View File

@ -124,9 +124,9 @@ public class SDKSynchronizer: Synchronizer {
public private(set) var progress: Float = 0.0 public private(set) var progress: Float = 0.0
public private(set) var blockProcessor: CompactBlockProcessor public private(set) var blockProcessor: CompactBlockProcessor
public private(set) var initializer: Initializer public private(set) var initializer: Initializer
public private(set)var latestScannedHeight: BlockHeight public private(set) var latestScannedHeight: BlockHeight
public private(set) var connectionState: ConnectionState public private(set) var connectionState: ConnectionState
public private(set) var network: ZcashNetwork
private var transactionManager: OutboundTransactionManager private var transactionManager: OutboundTransactionManager
private var transactionRepository: TransactionRepository private var transactionRepository: TransactionRepository
private var utxoRepository: UnspentTransactionOutputRepository private var utxoRepository: UnspentTransactionOutputRepository
@ -159,7 +159,8 @@ public class SDKSynchronizer: Synchronizer {
self.utxoRepository = utxoRepository self.utxoRepository = utxoRepository
self.blockProcessor = blockProcessor self.blockProcessor = blockProcessor
self.latestScannedHeight = (try? transactionRepository.lastScannedHeight()) ?? initializer.walletBirthday.height self.latestScannedHeight = (try? transactionRepository.lastScannedHeight()) ?? initializer.walletBirthday.height
self.subscribeToProcessorNotifications(self.blockProcessor) self.network = initializer.network
self.subscribeToProcessorNotifications(blockProcessor)
} }
deinit { deinit {
@ -443,13 +444,14 @@ public class SDKSynchronizer: Synchronizer {
public func shieldFunds(spendingKey: String, transparentSecretKey: String, memo: String?, from accountIndex: Int, resultBlock: @escaping (Result<PendingTransactionEntity, Error>) -> Void) { public func shieldFunds(spendingKey: String, transparentSecretKey: String, memo: String?, from accountIndex: Int, resultBlock: @escaping (Result<PendingTransactionEntity, Error>) -> Void) {
// let's see if there are funds to shield // let's see if there are funds to shield
let derivationTool = DerivationTool.default let derivationTool = DerivationTool(networkType: self.network.networkType)
do { do {
let tAddr = try derivationTool.deriveTransparentAddressFromPrivateKey(transparentSecretKey) let tAddr = try derivationTool.deriveTransparentAddressFromPrivateKey(transparentSecretKey)
let tBalance = try utxoRepository.balance(address: tAddr, latestHeight: self.latestDownloadedHeight()) let tBalance = try utxoRepository.balance(address: tAddr, latestHeight: self.latestDownloadedHeight())
guard tBalance.verified >= ZcashSDK.shieldingThreshold else { // Verify that at least there are funds for the fee. Ideally this logic will be improved by the shielding wallet.
guard tBalance.verified >= self.network.constants.defaultFee(for: self.latestScannedHeight) else {
resultBlock(.failure(ShieldFundsError.insuficientTransparentFunds)) resultBlock(.failure(ShieldFundsError.insuficientTransparentFunds))
return return
} }
@ -562,7 +564,7 @@ public class SDKSynchronizer: Synchronizer {
return return
} }
initializer.lightWalletService.fetchUTXOs(for: address, height: ZcashSDK.SAPLING_ACTIVATION_HEIGHT, result: { [weak self] r in initializer.lightWalletService.fetchUTXOs(for: address, height: network.constants.SAPLING_ACTIVATION_HEIGHT, result: { [weak self] r in
guard let self = self else { return } guard let self = self else { return }
switch r { switch r {
case .success(let utxos): case .success(let utxos):
@ -579,7 +581,7 @@ public class SDKSynchronizer: Synchronizer {
}) })
} }
public func refreshUTXOs(address: String, from height: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT, result: @escaping (Result<RefreshedUTXOs, Error>) -> Void) { public func refreshUTXOs(address: String, from height: BlockHeight, result: @escaping (Result<RefreshedUTXOs, Error>) -> Void) {
self.blockProcessor.refreshUTXOs(tAddress: address, startHeight: height, result: result) self.blockProcessor.refreshUTXOs(tAddress: address, startHeight: height, result: result)
} }
@ -635,7 +637,7 @@ public class SDKSynchronizer: Synchronizer {
height = rewindHeight height = rewindHeight
case .transaction(let tx): case .transaction(let tx):
guard let txHeight = tx.anchor else { guard let txHeight = tx.anchor(network: self.network) else {
throw SynchronizerError.rewindErrorUnknownArchorHeight throw SynchronizerError.rewindErrorUnknownArchorHeight
} }
height = txHeight height = txHeight
@ -846,4 +848,3 @@ fileprivate struct NullProgress: BlockProgressReporting {
0 0
} }
} }

View File

@ -13,7 +13,7 @@ typedef struct {
uintptr_t len; uintptr_t len;
} FFIUVKBoxedSlice; } FFIUVKBoxedSlice;
int32_t zcashlc_branch_id_for_height(int32_t height); int32_t zcashlc_branch_id_for_height(int32_t height, uint32_t network_id);
/** /**
* Clears the record of the last error message. * Clears the record of the last error message.
@ -23,7 +23,8 @@ void zcashlc_clear_last_error(void);
int32_t zcashlc_clear_utxos(const uint8_t *db_data, int32_t zcashlc_clear_utxos(const uint8_t *db_data,
uintptr_t db_data_len, uintptr_t db_data_len,
const char *taddress, const char *taddress,
int32_t above_height); int32_t above_height,
uint32_t network_id);
/** /**
* Creates a transaction paying the specified address from the given account. * Creates a transaction paying the specified address from the given account.
@ -45,18 +46,20 @@ int64_t zcashlc_create_to_address(const uint8_t *db_data,
const uint8_t *spend_params, const uint8_t *spend_params,
uintptr_t spend_params_len, uintptr_t spend_params_len,
const uint8_t *output_params, const uint8_t *output_params,
uintptr_t output_params_len); uintptr_t output_params_len,
uint32_t network_id);
int32_t zcashlc_decrypt_and_store_transaction(const uint8_t *db_data, int32_t zcashlc_decrypt_and_store_transaction(const uint8_t *db_data,
uintptr_t db_data_len, uintptr_t db_data_len,
const uint8_t *tx, const uint8_t *tx,
uintptr_t tx_len); uintptr_t tx_len,
uint32_t network_id);
/** /**
* derives a shielded address from the given extended full viewing key. * derives a shielded address from the given extended full viewing key.
* call zcashlc_string_free with the returned pointer when done using it * call zcashlc_string_free with the returned pointer when done using it
*/ */
char *zcashlc_derive_extended_full_viewing_key(const char *extsk); char *zcashlc_derive_extended_full_viewing_key(const char *extsk, uint32_t network_id);
/** /**
* Derives Extended Full Viewing Keys from the given seed into 'accounts' number of accounts. * Derives Extended Full Viewing Keys from the given seed into 'accounts' number of accounts.
@ -68,7 +71,8 @@ char *zcashlc_derive_extended_full_viewing_key(const char *extsk);
char **zcashlc_derive_extended_full_viewing_keys(const uint8_t *seed, char **zcashlc_derive_extended_full_viewing_keys(const uint8_t *seed,
uintptr_t seed_len, uintptr_t seed_len,
int32_t accounts, int32_t accounts,
uintptr_t *capacity_ret); uintptr_t *capacity_ret,
uint32_t network_id);
/** /**
* Derives Extended Spending Keys from the given seed into 'accounts' number of accounts. * Derives Extended Spending Keys from the given seed into 'accounts' number of accounts.
@ -80,7 +84,8 @@ char **zcashlc_derive_extended_full_viewing_keys(const uint8_t *seed,
char **zcashlc_derive_extended_spending_keys(const uint8_t *seed, char **zcashlc_derive_extended_spending_keys(const uint8_t *seed,
uintptr_t seed_len, uintptr_t seed_len,
int32_t accounts, int32_t accounts,
uintptr_t *capacity_ret); uintptr_t *capacity_ret,
uint32_t network_id);
/** /**
* derives a shielded address from the given seed. * derives a shielded address from the given seed.
@ -88,24 +93,25 @@ char **zcashlc_derive_extended_spending_keys(const uint8_t *seed,
*/ */
char *zcashlc_derive_shielded_address_from_seed(const uint8_t *seed, char *zcashlc_derive_shielded_address_from_seed(const uint8_t *seed,
uintptr_t seed_len, uintptr_t seed_len,
int32_t account_index); int32_t account_index,
uint32_t network_id);
/** /**
* derives a shielded address from the given viewing key. * derives a shielded address from the given viewing key.
* call zcashlc_string_free with the returned pointer when done using it * call zcashlc_string_free with the returned pointer when done using it
*/ */
char *zcashlc_derive_shielded_address_from_viewing_key(const char *extfvk); char *zcashlc_derive_shielded_address_from_viewing_key(const char *extfvk, uint32_t network_id);
/** /**
* derives a shielded address from the given viewing key. * derives a shielded address from the given viewing key.
* call zcashlc_string_free with the returned pointer when done using it * call zcashlc_string_free with the returned pointer when done using it
*/ */
char *zcashlc_derive_transparent_address_from_public_key(const char *pubkey); char *zcashlc_derive_transparent_address_from_public_key(const char *pubkey, uint32_t network_id);
/** /**
* Derives a transparent address from the given secret key enconded as a WIF string * Derives a transparent address from the given secret key enconded as a WIF string
*/ */
char *zcashlc_derive_transparent_address_from_secret_key(const char *tsk); char *zcashlc_derive_transparent_address_from_secret_key(const char *tsk, uint32_t network_id);
/** /**
* Derives a transparent address from the given seed * Derives a transparent address from the given seed
@ -113,7 +119,8 @@ char *zcashlc_derive_transparent_address_from_secret_key(const char *tsk);
char *zcashlc_derive_transparent_address_from_seed(const uint8_t *seed, char *zcashlc_derive_transparent_address_from_seed(const uint8_t *seed,
uintptr_t seed_len, uintptr_t seed_len,
int32_t account, int32_t account,
int32_t index); int32_t index,
uint32_t network_id);
/** /**
* TEST TEST 123 TEST * TEST TEST 123 TEST
@ -124,11 +131,13 @@ char *zcashlc_derive_transparent_address_from_seed(const uint8_t *seed,
char *zcashlc_derive_transparent_private_key_from_seed(const uint8_t *seed, char *zcashlc_derive_transparent_private_key_from_seed(const uint8_t *seed,
uintptr_t seed_len, uintptr_t seed_len,
int32_t account, int32_t account,
int32_t index); int32_t index,
uint32_t network_id);
FFIUVKBoxedSlice *zcashlc_derive_unified_viewing_keys_from_seed(const uint8_t *seed, FFIUVKBoxedSlice *zcashlc_derive_unified_viewing_keys_from_seed(const uint8_t *seed,
uintptr_t seed_len, uintptr_t seed_len,
int32_t accounts); int32_t accounts,
uint32_t network_id);
/** /**
* Copies the last error message into the provided allocated buffer. * Copies the last error message into the provided allocated buffer.
@ -142,16 +151,23 @@ void zcashlc_free_uvk_array(FFIUVKBoxedSlice *uvks);
* *
* Call `zcashlc_string_free` on the returned pointer when you are finished with it. * Call `zcashlc_string_free` on the returned pointer when you are finished with it.
*/ */
char *zcashlc_get_address(const uint8_t *db_data, uintptr_t db_data_len, int32_t account); char *zcashlc_get_address(const uint8_t *db_data,
uintptr_t db_data_len,
int32_t account,
uint32_t network_id);
/** /**
* Returns the balance for the account, including all unspent notes that we know about. * Returns the balance for the account, including all unspent notes that we know about.
*/ */
int64_t zcashlc_get_balance(const uint8_t *db_data, uintptr_t db_data_len, int32_t account); int64_t zcashlc_get_balance(const uint8_t *db_data,
uintptr_t db_data_len,
int32_t account,
uint32_t network_id);
int32_t zcashlc_get_nearest_rewind_height(const uint8_t *db_data, int32_t zcashlc_get_nearest_rewind_height(const uint8_t *db_data,
uintptr_t db_data_len, uintptr_t db_data_len,
int32_t height); int32_t height,
uint32_t network_id);
/** /**
* Returns the memo for a received note, if it is known and a valid UTF-8 string. * Returns the memo for a received note, if it is known and a valid UTF-8 string.
@ -163,7 +179,8 @@ int32_t zcashlc_get_nearest_rewind_height(const uint8_t *db_data,
*/ */
char *zcashlc_get_received_memo_as_utf8(const uint8_t *db_data, char *zcashlc_get_received_memo_as_utf8(const uint8_t *db_data,
uintptr_t db_data_len, uintptr_t db_data_len,
int64_t id_note); int64_t id_note,
uint32_t network_id);
/** /**
* Returns the memo for a sent note, if it is known and a valid UTF-8 string. * Returns the memo for a sent note, if it is known and a valid UTF-8 string.
@ -173,7 +190,10 @@ char *zcashlc_get_received_memo_as_utf8(const uint8_t *db_data,
* *
* Call `zcashlc_string_free` on the returned pointer when you are finished with it. * Call `zcashlc_string_free` on the returned pointer when you are finished with it.
*/ */
char *zcashlc_get_sent_memo_as_utf8(const uint8_t *db_data, uintptr_t db_data_len, int64_t id_note); char *zcashlc_get_sent_memo_as_utf8(const uint8_t *db_data,
uintptr_t db_data_len,
int64_t id_note,
uint32_t network_id);
/** /**
* Returns the verified transparent balance for the address, which ignores utxos that have been * Returns the verified transparent balance for the address, which ignores utxos that have been
@ -181,7 +201,8 @@ char *zcashlc_get_sent_memo_as_utf8(const uint8_t *db_data, uintptr_t db_data_le
*/ */
int64_t zcashlc_get_total_transparent_balance(const uint8_t *db_data, int64_t zcashlc_get_total_transparent_balance(const uint8_t *db_data,
uintptr_t db_data_len, uintptr_t db_data_len,
const char *address); const char *address,
uint32_t network_id);
/** /**
* Returns the verified balance for the account, which ignores notes that have been * Returns the verified balance for the account, which ignores notes that have been
@ -189,7 +210,8 @@ int64_t zcashlc_get_total_transparent_balance(const uint8_t *db_data,
*/ */
int64_t zcashlc_get_verified_balance(const uint8_t *db_data, int64_t zcashlc_get_verified_balance(const uint8_t *db_data,
uintptr_t db_data_len, uintptr_t db_data_len,
int32_t account); int32_t account,
uint32_t network_id);
/** /**
* Returns the verified transparent balance for the address, which ignores utxos that have been * Returns the verified transparent balance for the address, which ignores utxos that have been
@ -197,7 +219,8 @@ int64_t zcashlc_get_verified_balance(const uint8_t *db_data,
*/ */
int64_t zcashlc_get_verified_transparent_balance(const uint8_t *db_data, int64_t zcashlc_get_verified_transparent_balance(const uint8_t *db_data,
uintptr_t db_data_len, uintptr_t db_data_len,
const char *address); const char *address,
uint32_t network_id);
/** /**
* Initialises the data database with the given number of accounts using the given seed. * Initialises the data database with the given number of accounts using the given seed.
@ -212,7 +235,8 @@ char **zcashlc_init_accounts_table(const uint8_t *db_data,
const uint8_t *seed, const uint8_t *seed,
uintptr_t seed_len, uintptr_t seed_len,
int32_t accounts, int32_t accounts,
uintptr_t *capacity_ret); uintptr_t *capacity_ret,
uint32_t network_id);
/** /**
* Initialises the data database with the given extended full viewing keys * Initialises the data database with the given extended full viewing keys
@ -220,7 +244,8 @@ char **zcashlc_init_accounts_table(const uint8_t *db_data,
*/ */
bool zcashlc_init_accounts_table_with_keys(const uint8_t *db_data, bool zcashlc_init_accounts_table_with_keys(const uint8_t *db_data,
uintptr_t db_data_len, uintptr_t db_data_len,
FFIUVKBoxedSlice *uvks); FFIUVKBoxedSlice *uvks,
uint32_t network_id);
/** /**
* Initialises the data database with the given block. * Initialises the data database with the given block.
@ -233,30 +258,33 @@ int32_t zcashlc_init_blocks_table(const uint8_t *db_data,
int32_t height, int32_t height,
const char *hash_hex, const char *hash_hex,
uint32_t time, uint32_t time,
const char *sapling_tree_hex); const char *sapling_tree_hex,
uint32_t network_id);
/** /**
* Sets up the internal structure of the data database. * Sets up the internal structure of the data database.
*/ */
int32_t zcashlc_init_data_database(const uint8_t *db_data, uintptr_t db_data_len); int32_t zcashlc_init_data_database(const uint8_t *db_data,
uintptr_t db_data_len,
uint32_t network_id);
/** /**
* Returns true when the address is valid and shielded. * Returns true when the address is valid and shielded.
* Returns false in any other case * Returns false in any other case
* Errors when the provided address belongs to another network * Errors when the provided address belongs to another network
*/ */
bool zcashlc_is_valid_shielded_address(const char *address); bool zcashlc_is_valid_shielded_address(const char *address, uint32_t network_id);
/** /**
* Returns true when the address is valid and transparent. * Returns true when the address is valid and transparent.
* Returns false in any other case * Returns false in any other case
*/ */
bool zcashlc_is_valid_transparent_address(const char *address); bool zcashlc_is_valid_transparent_address(const char *address, uint32_t network_id);
/** /**
* returns whether the given viewing key is valid or not * returns whether the given viewing key is valid or not
*/ */
bool zcashlc_is_valid_viewing_key(const char *key); bool zcashlc_is_valid_viewing_key(const char *key, uint32_t network_id);
/** /**
* Returns the length of the last error message to be logged. * Returns the length of the last error message to be logged.
@ -272,7 +300,8 @@ bool zcashlc_put_utxo(const uint8_t *db_data,
const uint8_t *script_bytes, const uint8_t *script_bytes,
uintptr_t script_bytes_len, uintptr_t script_bytes_len,
int64_t value, int64_t value,
int32_t height); int32_t height,
uint32_t network_id);
/** /**
* Rewinds the data database to the given height. * Rewinds the data database to the given height.
@ -280,7 +309,10 @@ bool zcashlc_put_utxo(const uint8_t *db_data,
* If the requested height is greater than or equal to the height of the last scanned * If the requested height is greater than or equal to the height of the last scanned
* block, this function does nothing. * block, this function does nothing.
*/ */
bool zcashlc_rewind_to_height(const uint8_t *db_data, uintptr_t db_data_len, int32_t height); bool zcashlc_rewind_to_height(const uint8_t *db_data,
uintptr_t db_data_len,
int32_t height,
uint32_t network_id);
/** /**
* Scans new blocks added to the cache for any transactions received by the tracked * Scans new blocks added to the cache for any transactions received by the tracked
@ -302,7 +334,8 @@ int32_t zcashlc_scan_blocks(const uint8_t *db_cache,
uintptr_t db_cache_len, uintptr_t db_cache_len,
const uint8_t *db_data, const uint8_t *db_data,
uintptr_t db_data_len, uintptr_t db_data_len,
uint32_t scan_limit); uint32_t scan_limit,
uint32_t network_id);
int64_t zcashlc_shield_funds(const uint8_t *db_data, int64_t zcashlc_shield_funds(const uint8_t *db_data,
uintptr_t db_data_len, uintptr_t db_data_len,
@ -313,7 +346,8 @@ int64_t zcashlc_shield_funds(const uint8_t *db_data,
const uint8_t *spend_params, const uint8_t *spend_params,
uintptr_t spend_params_len, uintptr_t spend_params_len,
const uint8_t *output_params, const uint8_t *output_params,
uintptr_t output_params_len); uintptr_t output_params_len,
uint32_t network_id);
/** /**
* Frees strings returned by other zcashlc functions. * Frees strings returned by other zcashlc functions.
@ -341,7 +375,8 @@ void zcashlc_string_free(char *s);
int32_t zcashlc_validate_combined_chain(const uint8_t *db_cache, int32_t zcashlc_validate_combined_chain(const uint8_t *db_cache,
uintptr_t db_cache_len, uintptr_t db_cache_len,
const uint8_t *db_data, const uint8_t *db_data,
uintptr_t db_data_len); uintptr_t db_data_len,
uint32_t network_id);
/** /**
* Frees vectors of strings returned by other zcashlc functions. * Frees vectors of strings returned by other zcashlc functions.

View File

@ -24,12 +24,15 @@ class AdvancedReOrgTests: XCTestCase {
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg") var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
let branchID = "2bb40e60" let branchID = "2bb40e60"
let chainName = "main" let chainName = "main"
let network = DarksideWalletDNetwork()
override func setUpWithError() throws { override func setUpWithError() throws {
coordinator = try TestCoordinator( coordinator = try TestCoordinator(
seed: seedPhrase, seed: seedPhrase,
walletBirthday: birthday, walletBirthday: birthday,
channelProvider: ChannelProvider() channelProvider: ChannelProvider(),
network: network
) )
try coordinator.reset(saplingActivation: 663150, branchID: self.branchID, chainName: self.chainName) try coordinator.reset(saplingActivation: 663150, branchID: self.branchID, chainName: self.chainName)
} }

View File

@ -20,12 +20,14 @@ class BalanceTests: XCTestCase {
let chainName = "main" let chainName = "main"
var syncedExpectation = XCTestExpectation(description: "synced") var syncedExpectation = XCTestExpectation(description: "synced")
var sentTransactionExpectation = XCTestExpectation(description: "sent") var sentTransactionExpectation = XCTestExpectation(description: "sent")
let network: ZcashNetwork = DarksideWalletDNetwork()
override func setUpWithError() throws { override func setUpWithError() throws {
coordinator = try TestCoordinator( coordinator = try TestCoordinator(
seed: seedPhrase, seed: seedPhrase,
walletBirthday: birthday, walletBirthday: birthday,
channelProvider: ChannelProvider() channelProvider: ChannelProvider(),
network: network
) )
try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main") try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main")
@ -58,10 +60,10 @@ class BalanceTests: XCTestCase {
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let totalBalance = coordinator.synchronizer.initializer.getBalance() let totalBalance = coordinator.synchronizer.initializer.getBalance()
XCTAssertTrue(verifiedBalance > ZcashSDK.defaultFee()) XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: defaultLatestHeight))
XCTAssertEqual(verifiedBalance, totalBalance) XCTAssertEqual(verifiedBalance, totalBalance)
let maxBalance = verifiedBalance - Int64(ZcashSDK.defaultFee()) let maxBalance = verifiedBalance - Int64(network.constants.defaultFee(for: defaultLatestHeight))
// 3 create a transaction for the max amount possible // 3 create a transaction for the max amount possible
// 4 send the transaction // 4 send the transaction
@ -196,10 +198,10 @@ class BalanceTests: XCTestCase {
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let totalBalance = coordinator.synchronizer.initializer.getBalance() let totalBalance = coordinator.synchronizer.initializer.getBalance()
XCTAssertTrue(verifiedBalance > ZcashSDK.defaultFee()) XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: defaultLatestHeight))
XCTAssertEqual(verifiedBalance, totalBalance) XCTAssertEqual(verifiedBalance, totalBalance)
let maxBalanceMinusOne = verifiedBalance - Int64(ZcashSDK.defaultFee()) - 1 let maxBalanceMinusOne = verifiedBalance - Int64(network.constants.defaultFee(for: defaultLatestHeight)) - 1
// 3 create a transaction for the max amount possible // 3 create a transaction for the max amount possible
// 4 send the transaction // 4 send the transaction
@ -333,10 +335,10 @@ class BalanceTests: XCTestCase {
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let totalBalance = coordinator.synchronizer.initializer.getBalance() let totalBalance = coordinator.synchronizer.initializer.getBalance()
XCTAssertTrue(verifiedBalance > ZcashSDK.defaultFee()) XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: defaultLatestHeight))
XCTAssertEqual(verifiedBalance, totalBalance) XCTAssertEqual(verifiedBalance, totalBalance)
let maxBalanceMinusOne = 100000 - ZcashSDK.defaultFee() let maxBalanceMinusOne = 100000 - network.constants.defaultFee(for: defaultLatestHeight)
// 3 create a transaction for the max amount possible // 3 create a transaction for the max amount possible
// 4 send the transaction // 4 send the transaction
@ -483,7 +485,7 @@ class BalanceTests: XCTestCase {
/* /*
there's more zatoshi to send than network fee there's more zatoshi to send than network fee
*/ */
XCTAssertTrue(presendVerifiedBalance >= (Int64(ZcashSDK.MINERS_FEE_ZATOSHI) + sendAmount)) XCTAssertTrue(presendVerifiedBalance >= (Int64(network.constants.defaultFee(for: defaultLatestHeight)) + sendAmount))
var pendingTx: PendingTransactionEntity? var pendingTx: PendingTransactionEntity?
coordinator.synchronizer.sendToAddress(spendingKey: spendingKey, coordinator.synchronizer.sendToAddress(spendingKey: spendingKey,
@ -540,8 +542,8 @@ class BalanceTests: XCTestCase {
wait(for: [mineExpectation], timeout: 5) wait(for: [mineExpectation], timeout: 5)
XCTAssertEqual(presendVerifiedBalance - self.sendAmount - ZcashSDK.defaultFee(),coordinator.synchronizer.initializer.getBalance()) XCTAssertEqual(presendVerifiedBalance - self.sendAmount - network.constants.defaultFee(for: defaultLatestHeight),coordinator.synchronizer.initializer.getBalance())
XCTAssertEqual(presendVerifiedBalance - self.sendAmount - ZcashSDK.defaultFee(),coordinator.synchronizer.initializer.getVerifiedBalance()) XCTAssertEqual(presendVerifiedBalance - self.sendAmount - network.constants.defaultFee(for: defaultLatestHeight),coordinator.synchronizer.initializer.getVerifiedBalance())
guard let transaction = pendingTx else { guard let transaction = pendingTx else {
XCTFail("pending transaction nil") XCTFail("pending transaction nil")
@ -629,7 +631,7 @@ class BalanceTests: XCTestCase {
} }
let presendBalance = coordinator.synchronizer.initializer.getBalance() let presendBalance = coordinator.synchronizer.initializer.getBalance()
XCTAssertTrue(presendBalance >= (Int64(ZcashSDK.defaultFee()) + sendAmount)) // there's more zatoshi to send than network fee XCTAssertTrue(presendBalance >= (Int64(network.constants.defaultFee(for: defaultLatestHeight)) + sendAmount)) // there's more zatoshi to send than network fee
var pendingTx: PendingTransactionEntity? var pendingTx: PendingTransactionEntity?
@ -667,7 +669,7 @@ class BalanceTests: XCTestCase {
XCTAssertEqual(Int64(transaction.value), self.sendAmount) XCTAssertEqual(Int64(transaction.value), self.sendAmount)
XCTAssertEqual(self.coordinator.synchronizer.initializer.getBalance(), presendBalance - Int64(self.sendAmount) - ZcashSDK.defaultFee()) XCTAssertEqual(self.coordinator.synchronizer.initializer.getBalance(), presendBalance - Int64(self.sendAmount) - network.constants.defaultFee(for: defaultLatestHeight))
XCTAssertNil(transaction.errorCode) XCTAssertNil(transaction.errorCode)
@ -697,7 +699,7 @@ class BalanceTests: XCTestCase {
wait(for: [mineExpectation], timeout: 5) wait(for: [mineExpectation], timeout: 5)
XCTAssertEqual(presendBalance - self.sendAmount - Int64(ZcashSDK.defaultFee()),coordinator.synchronizer.initializer.getBalance()) XCTAssertEqual(presendBalance - self.sendAmount - Int64(network.constants.defaultFee(for: defaultLatestHeight)),coordinator.synchronizer.initializer.getBalance())
} }
/** /**
@ -869,7 +871,7 @@ class BalanceTests: XCTestCase {
/* /*
Theres a change note of value (previous note value - sent amount) Theres a change note of value (previous note value - sent amount)
*/ */
XCTAssertEqual(previousVerifiedBalance - self.sendAmount - ZcashSDK.defaultFee(), Int64(receivedNote.value)) XCTAssertEqual(previousVerifiedBalance - self.sendAmount - self.network.constants.defaultFee(for: self.defaultLatestHeight), Int64(receivedNote.value))
/* /*
@ -1024,7 +1026,7 @@ class BalanceTests: XCTestCase {
func totalBalanceValidation(totalBalance: Int64, func totalBalanceValidation(totalBalance: Int64,
previousTotalbalance: Int64, previousTotalbalance: Int64,
sentAmount: Int64) { sentAmount: Int64) {
XCTAssertEqual(totalBalance, previousTotalbalance - sentAmount - Int64(ZcashSDK.MINERS_FEE_ZATOSHI)) XCTAssertEqual(totalBalance, previousTotalbalance - sentAmount - Int64(network.constants.defaultFee(for: defaultLatestHeight)))
} }
} }

View File

@ -24,17 +24,18 @@ class BlockBatchValidationTests: XCTestCase {
} }
func testBranchIdFailure() throws { func testBranchIdFailure() throws {
let service = MockLightWalletService(latestBlockHeight: 1210000) let network = ZcashNetworkBuilder.network(for: .mainnet)
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000) let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
let downloader = CompactBlockDownloader(service: service, storage: repository) let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: ZcashSDK.SAPLING_ACTIVATION_HEIGHT) let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.SAPLING_ACTIVATION_HEIGHT, network: network)
var info = LightdInfo() var info = LightdInfo()
info.blockHeight = 130000 info.blockHeight = 130000
info.branch = "d34db33f" info.branch = "d34db33f"
info.chainName = "main" info.chainName = "main"
info.buildUser = "test user" info.buildUser = "test user"
info.consensusBranchID = "d34db33f" info.consensusBranchID = "d34db33f"
info.saplingActivationHeight = UInt64(ZcashSDK.SAPLING_ACTIVATION_HEIGHT) info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
service.mockLightDInfo = info service.mockLightDInfo = info
let mockRust = MockRustBackend.self let mockRust = MockRustBackend.self
@ -63,17 +64,18 @@ class BlockBatchValidationTests: XCTestCase {
} }
func testBranchNetworkMismatchFailure() throws { func testBranchNetworkMismatchFailure() throws {
let service = MockLightWalletService(latestBlockHeight: 1210000) let network = ZcashNetworkBuilder.network(for: .mainnet)
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000) let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
let downloader = CompactBlockDownloader(service: service, storage: repository) let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: ZcashSDK.SAPLING_ACTIVATION_HEIGHT) let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.SAPLING_ACTIVATION_HEIGHT, network: network)
var info = LightdInfo() var info = LightdInfo()
info.blockHeight = 130000 info.blockHeight = 130000
info.branch = "d34db33f" info.branch = "d34db33f"
info.chainName = "test" info.chainName = "test"
info.buildUser = "test user" info.buildUser = "test user"
info.consensusBranchID = "d34db4d" info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(ZcashSDK.SAPLING_ACTIVATION_HEIGHT) info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
service.mockLightDInfo = info service.mockLightDInfo = info
let mockRust = MockRustBackend.self let mockRust = MockRustBackend.self
@ -103,17 +105,18 @@ class BlockBatchValidationTests: XCTestCase {
func testBranchNetworkTypeWrongFailure() throws { func testBranchNetworkTypeWrongFailure() throws {
let service = MockLightWalletService(latestBlockHeight: 1210000) let network = ZcashNetworkBuilder.network(for: .testnet)
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000) let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
let downloader = CompactBlockDownloader(service: service, storage: repository) let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: ZcashSDK.SAPLING_ACTIVATION_HEIGHT) let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.SAPLING_ACTIVATION_HEIGHT, network: network)
var info = LightdInfo() var info = LightdInfo()
info.blockHeight = 130000 info.blockHeight = 130000
info.branch = "d34db33f" info.branch = "d34db33f"
info.chainName = "another" info.chainName = "another"
info.buildUser = "test user" info.buildUser = "test user"
info.consensusBranchID = "d34db4d" info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(ZcashSDK.SAPLING_ACTIVATION_HEIGHT) info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
service.mockLightDInfo = info service.mockLightDInfo = info
let mockRust = MockRustBackend.self let mockRust = MockRustBackend.self
@ -142,10 +145,11 @@ class BlockBatchValidationTests: XCTestCase {
} }
func testSaplingActivationHeightMismatch() throws { func testSaplingActivationHeightMismatch() throws {
let service = MockLightWalletService(latestBlockHeight: 1210000) let network = ZcashNetworkBuilder.network(for: .mainnet)
let service = MockLightWalletService(latestBlockHeight: 1210000, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000) let repository = ZcashConsoleFakeStorage(latestBlockHeight: 1220000)
let downloader = CompactBlockDownloader(service: service, storage: repository) let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: ZcashSDK.SAPLING_ACTIVATION_HEIGHT) let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.SAPLING_ACTIVATION_HEIGHT, network: network)
var info = LightdInfo() var info = LightdInfo()
info.blockHeight = 130000 info.blockHeight = 130000
info.branch = "d34db33f" info.branch = "d34db33f"
@ -167,7 +171,7 @@ class BlockBatchValidationTests: XCTestCase {
operation.errorHandler = { error in operation.errorHandler = { error in
expectation.fulfill() expectation.fulfill()
switch error { switch error {
case CompactBlockProcessorError.saplingActivationMismatch(expected: ZcashSDK.SAPLING_ACTIVATION_HEIGHT, found: BlockHeight(info.saplingActivationHeight)): case CompactBlockProcessorError.saplingActivationMismatch(expected: network.constants.SAPLING_ACTIVATION_HEIGHT, found: BlockHeight(info.saplingActivationHeight)):
break break
default: default:
XCTFail("Expected CompactBlockProcessorError.saplingActivationMismatch but found \(error)") XCTFail("Expected CompactBlockProcessorError.saplingActivationMismatch but found \(error)")
@ -181,20 +185,22 @@ class BlockBatchValidationTests: XCTestCase {
} }
func testResultIsWait() throws { func testResultIsWait() throws {
let network = ZcashNetworkBuilder.network(for: .mainnet)
let expectedLatestHeight = BlockHeight(1210000) let expectedLatestHeight = BlockHeight(1210000)
let service = MockLightWalletService(latestBlockHeight: expectedLatestHeight) let service = MockLightWalletService(latestBlockHeight: expectedLatestHeight, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let expectedStoreLatestHeight = BlockHeight(1220000) let expectedStoreLatestHeight = BlockHeight(1220000)
let expectedResult = FigureNextBatchOperation.NextState.wait(latestHeight: expectedLatestHeight, latestDownloadHeight: expectedLatestHeight) let expectedResult = FigureNextBatchOperation.NextState.wait(latestHeight: expectedLatestHeight, latestDownloadHeight: expectedLatestHeight)
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight) let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
let downloader = CompactBlockDownloader(service: service, storage: repository) let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: ZcashSDK.SAPLING_ACTIVATION_HEIGHT) let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: 1210000, saplingActivation: network.constants.SAPLING_ACTIVATION_HEIGHT, network: network)
var info = LightdInfo() var info = LightdInfo()
info.blockHeight = UInt64(expectedLatestHeight) info.blockHeight = UInt64(expectedLatestHeight)
info.branch = "d34db33f" info.branch = "d34db33f"
info.chainName = "main" info.chainName = "main"
info.buildUser = "test user" info.buildUser = "test user"
info.consensusBranchID = "d34db4d" info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(ZcashSDK.SAPLING_ACTIVATION_HEIGHT) info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
service.mockLightDInfo = info service.mockLightDInfo = info
let mockRust = MockRustBackend.self let mockRust = MockRustBackend.self
@ -207,7 +213,7 @@ class BlockBatchValidationTests: XCTestCase {
startedExpectation.fulfill() startedExpectation.fulfill()
} }
operation.errorHandler = { error in operation.errorHandler = { error in
XCTFail("this shouldn't happen") XCTFail("this shouldn't happen: \(error)")
} }
operation.completionHandler = { (finished, cancelled) in operation.completionHandler = { (finished, cancelled) in
completedExpectation.fulfill() completedExpectation.fulfill()
@ -236,21 +242,22 @@ class BlockBatchValidationTests: XCTestCase {
} }
func testResultProcessNew() throws { func testResultProcessNew() throws {
let network = ZcashNetworkBuilder.network(for: .mainnet)
let expectedLatestHeight = BlockHeight(1230000) let expectedLatestHeight = BlockHeight(1230000)
let service = MockLightWalletService(latestBlockHeight: expectedLatestHeight) let service = MockLightWalletService(latestBlockHeight: expectedLatestHeight, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let expectedStoreLatestHeight = BlockHeight(1220000) let expectedStoreLatestHeight = BlockHeight(1220000)
let walletBirthday = BlockHeight(1210000) let walletBirthday = BlockHeight(1210000)
let expectedResult = FigureNextBatchOperation.NextState.processNewBlocks(range: CompactBlockProcessor.nextBatchBlockRange(latestHeight: expectedLatestHeight, latestDownloadedHeight: expectedStoreLatestHeight, walletBirthday: walletBirthday)) let expectedResult = FigureNextBatchOperation.NextState.processNewBlocks(range: CompactBlockProcessor.nextBatchBlockRange(latestHeight: expectedLatestHeight, latestDownloadedHeight: expectedStoreLatestHeight, walletBirthday: walletBirthday))
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight) let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
let downloader = CompactBlockDownloader(service: service, storage: repository) let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: walletBirthday, saplingActivation: ZcashSDK.SAPLING_ACTIVATION_HEIGHT) let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: walletBirthday, saplingActivation: network.constants.SAPLING_ACTIVATION_HEIGHT, network: network)
var info = LightdInfo() var info = LightdInfo()
info.blockHeight = UInt64(expectedLatestHeight) info.blockHeight = UInt64(expectedLatestHeight)
info.branch = "d34db33f" info.branch = "d34db33f"
info.chainName = "main" info.chainName = "main"
info.buildUser = "test user" info.buildUser = "test user"
info.consensusBranchID = "d34db4d" info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(ZcashSDK.SAPLING_ACTIVATION_HEIGHT) info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
service.mockLightDInfo = info service.mockLightDInfo = info
let mockRust = MockRustBackend.self let mockRust = MockRustBackend.self
@ -292,21 +299,22 @@ class BlockBatchValidationTests: XCTestCase {
} }
func testResultProcessorFinished() throws { func testResultProcessorFinished() throws {
let network = ZcashNetworkBuilder.network(for: .mainnet)
let expectedLatestHeight = BlockHeight(1230000) let expectedLatestHeight = BlockHeight(1230000)
let service = MockLightWalletService(latestBlockHeight: expectedLatestHeight) let service = MockLightWalletService(latestBlockHeight: expectedLatestHeight, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default))
let expectedStoreLatestHeight = BlockHeight(1230000) let expectedStoreLatestHeight = BlockHeight(1230000)
let walletBirthday = BlockHeight(1210000) let walletBirthday = BlockHeight(1210000)
let expectedResult = FigureNextBatchOperation.NextState.finishProcessing(height: expectedStoreLatestHeight) let expectedResult = FigureNextBatchOperation.NextState.finishProcessing(height: expectedStoreLatestHeight)
let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight) let repository = ZcashConsoleFakeStorage(latestBlockHeight: expectedStoreLatestHeight)
let downloader = CompactBlockDownloader(service: service, storage: repository) let downloader = CompactBlockDownloader(service: service, storage: repository)
let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: walletBirthday, saplingActivation: ZcashSDK.SAPLING_ACTIVATION_HEIGHT) let config = CompactBlockProcessor.Configuration(cacheDb: try! __cacheDbURL(), dataDb: try! __dataDbURL(), downloadBatchSize: 100, retries: 5, maxBackoffInterval: 10, rewindDistance: 100, walletBirthday: walletBirthday, saplingActivation: network.constants.SAPLING_ACTIVATION_HEIGHT, network: network)
var info = LightdInfo() var info = LightdInfo()
info.blockHeight = UInt64(expectedLatestHeight) info.blockHeight = UInt64(expectedLatestHeight)
info.branch = "d34db33f" info.branch = "d34db33f"
info.chainName = "main" info.chainName = "main"
info.buildUser = "test user" info.buildUser = "test user"
info.consensusBranchID = "d34db4d" info.consensusBranchID = "d34db4d"
info.saplingActivationHeight = UInt64(ZcashSDK.SAPLING_ACTIVATION_HEIGHT) info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
service.mockLightDInfo = info service.mockLightDInfo = info
let mockRust = MockRustBackend.self let mockRust = MockRustBackend.self

View File

@ -14,10 +14,18 @@ class BlockDownloaderTests: XCTestCase {
var service: LightWalletService! var service: LightWalletService!
var storage: CompactBlockRepository! var storage: CompactBlockRepository!
var cacheDB = try! __cacheDbURL() var cacheDB = try! __cacheDbURL()
override func setUp() { var network = DarksideWalletDNetwork()
var darksideWalletService: DarksideWalletService!
let branchID = "2bb40e60"
let chainName = "main"
override func setUpWithError() throws {
service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default) service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default)
storage = try! TestDbBuilder.diskCompactBlockStorage(at: cacheDB) storage = try! TestDbBuilder.diskCompactBlockStorage(at: cacheDB)
downloader = CompactBlockDownloader(service: service, storage: storage) downloader = CompactBlockDownloader(service: service, storage: storage)
darksideWalletService = DarksideWalletService(service: service as! LightWalletGRPCService)
try FakeChainBuilder.buildChain(darksideWallet: darksideWalletService, branchID: branchID, chainName: chainName)
try darksideWalletService.applyStaged(nextLatestHeight: 663250)
} }
override func tearDown() { override func tearDown() {
@ -32,8 +40,8 @@ class BlockDownloaderTests: XCTestCase {
let expect = XCTestExpectation(description: self.description) let expect = XCTestExpectation(description: self.description)
expect.expectedFulfillmentCount = 3 expect.expectedFulfillmentCount = 3
let lowerRange: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT let lowerRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT
let upperRange: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 99 let upperRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT + 99
let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange)) let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange))
downloader.downloadBlockRange(range) { (error) in downloader.downloadBlockRange(range) { (error) in
@ -58,8 +66,8 @@ class BlockDownloaderTests: XCTestCase {
func testSmallDownload() { func testSmallDownload() {
let lowerRange: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT let lowerRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT
let upperRange: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 99 let upperRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT + 99
let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange)) let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange))
var latest: BlockHeight = 0 var latest: BlockHeight = 0
@ -86,12 +94,12 @@ class BlockDownloaderTests: XCTestCase {
} }
func testFailure() { func testFailure() {
let awfulDownloader = CompactBlockDownloader(service: AwfulLightWalletService(latestBlockHeight: ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 1000), storage: ZcashConsoleFakeStorage()) let awfulDownloader = CompactBlockDownloader(service: AwfulLightWalletService(latestBlockHeight: self.network.constants.SAPLING_ACTIVATION_HEIGHT + 1000, service: darksideWalletService), storage: ZcashConsoleFakeStorage())
let expect = XCTestExpectation(description: self.description) let expect = XCTestExpectation(description: self.description)
expect.expectedFulfillmentCount = 1 expect.expectedFulfillmentCount = 1
let lowerRange: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT let lowerRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT
let upperRange: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 99 let upperRange: BlockHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT + 99
let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange)) let range = CompactBlockRange(uncheckedBounds: (lowerRange,upperRange))

View File

@ -20,9 +20,9 @@ class BlockScanOperationTests: XCTestCase {
extpub: "02075a7f5f7507d64022dad5954849f216b0f1b09b2d588be663d8e7faeb5aaf61") extpub: "02075a7f5f7507d64022dad5954849f216b0f1b09b2d588be663d8e7faeb5aaf61")
var walletBirthDay = WalletBirthday.birthday(with: 1386000) var walletBirthDay = WalletBirthday.birthday(with: 1386000, network: ZcashNetworkBuilder.network(for: .testnet))
var network = ZcashNetworkBuilder.network(for: .testnet)
var blockRepository: BlockRepository! var blockRepository: BlockRepository!
override func setUp() { override func setUp() {
// Put setup code here. This method is called before the invocation of each test method in the class. // Put setup code here. This method is called before the invocation of each test method in the class.
@ -47,17 +47,17 @@ class BlockScanOperationTests: XCTestCase {
func testSingleDownloadAndScanOperation() { func testSingleDownloadAndScanOperation() {
logger = SampleLogger(logLevel: .debug) logger = SampleLogger(logLevel: .debug)
XCTAssertNoThrow(try rustWelding.initDataDb(dbData: dataDbURL)) XCTAssertNoThrow(try rustWelding.initDataDb(dbData: dataDbURL, networkType: network.networkType))
let downloadStartedExpect = XCTestExpectation(description: self.description + "download started") let downloadStartedExpect = XCTestExpectation(description: self.description + "download started")
let downloadExpect = XCTestExpectation(description: self.description + "download") let downloadExpect = XCTestExpectation(description: self.description + "download")
let scanStartedExpect = XCTestExpectation(description: self.description + "scan started") let scanStartedExpect = XCTestExpectation(description: self.description + "scan started")
let scanExpect = XCTestExpectation(description: self.description + "scan") let scanExpect = XCTestExpectation(description: self.description + "scan")
let latestScannedBlockExpect = XCTestExpectation(description: self.description + "latestScannedHeight") let latestScannedBlockExpect = XCTestExpectation(description: self.description + "latestScannedHeight")
let service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default) let service = LightWalletGRPCService(endpoint: LightWalletEndpoint(address: "lightwalletd.testnet.electriccoin.co", port: 9067))
let blockCount = 100 let blockCount = 100
let range = ZcashSDK.SAPLING_ACTIVATION_HEIGHT ... ZcashSDK.SAPLING_ACTIVATION_HEIGHT + blockCount let range = network.constants.SAPLING_ACTIVATION_HEIGHT ... network.constants.SAPLING_ACTIVATION_HEIGHT + blockCount
let downloadOperation = CompactBlockDownloadOperation(downloader: CompactBlockDownloader.sqlDownloader(service: service, at: cacheDbURL)!, range: range) let downloadOperation = CompactBlockDownloadOperation(downloader: CompactBlockDownloader.sqlDownloader(service: service, at: cacheDbURL)!, range: range)
let scanOperation = CompactBlockScanningOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL) let scanOperation = CompactBlockScanningOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL, networkType: network.networkType)
downloadOperation.startedHandler = { downloadOperation.startedHandler = {
downloadStartedExpect.fulfill() downloadStartedExpect.fulfill()
@ -119,15 +119,15 @@ class BlockScanOperationTests: XCTestCase {
NotificationCenter.default.addObserver(self, selector: #selector(observeBenchmark(_:)), name: SDKMetrics.notificationName, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(observeBenchmark(_:)), name: SDKMetrics.notificationName, object: nil)
try self.rustWelding.initDataDb(dbData: dataDbURL) try self.rustWelding.initDataDb(dbData: dataDbURL, networkType: network.networkType)
guard try self.rustWelding.initAccountsTable(dbData: self.dataDbURL, uvks: [uvk]) else { guard try self.rustWelding.initAccountsTable(dbData: self.dataDbURL, uvks: [uvk], networkType: network.networkType) else {
XCTFail("failed to init account table") XCTFail("failed to init account table")
return return
} }
try self.rustWelding.initBlocksTable(dbData: dataDbURL, height: Int32(walletBirthDay.height), hash: walletBirthDay.hash, time: walletBirthDay.time, saplingTree: walletBirthDay.tree) try self.rustWelding.initBlocksTable(dbData: dataDbURL, height: Int32(walletBirthDay.height), hash: walletBirthDay.hash, time: walletBirthDay.time, saplingTree: walletBirthDay.tree, networkType: network.networkType)
let service = LightWalletGRPCService(host: Constants.address, port: 9067, secure: true, singleCallTimeout: 100000, streamingCallTimeout: 1000000000) let service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet)
let storage = CompactBlockStorage(url: cacheDbURL, readonly: false) let storage = CompactBlockStorage(url: cacheDbURL, readonly: false)
try storage.createTable() try storage.createTable()
@ -161,7 +161,7 @@ class BlockScanOperationTests: XCTestCase {
} }
let validationOperation = CompactBlockValidationOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL) let validationOperation = CompactBlockValidationOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL, networkType: network.networkType)
validationOperation.errorHandler = { error in validationOperation.errorHandler = { error in
self.operationQueue.cancelAllOperations() self.operationQueue.cancelAllOperations()
XCTFail("failed with error \(error)") XCTFail("failed with error \(error)")
@ -174,7 +174,7 @@ class BlockScanOperationTests: XCTestCase {
} }
let transactionRepository = TransactionRepositoryBuilder.build(dataDbURL: dataDbURL) let transactionRepository = TransactionRepositoryBuilder.build(dataDbURL: dataDbURL)
let scanningOperation = CompactBlockBatchScanningOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL, transactionRepository: transactionRepository, range: CompactBlockRange(uncheckedBounds: (walletBirthDay.height, walletBirthDay.height + 10000)), batchSize: 1000, progressDelegate: self) let scanningOperation = CompactBlockBatchScanningOperation(rustWelding: rustWelding, cacheDb: cacheDbURL, dataDb: dataDbURL, transactionRepository: transactionRepository, range: CompactBlockRange(uncheckedBounds: (walletBirthDay.height, walletBirthDay.height + 10000)), batchSize: 1000, networkType: network.networkType, progressDelegate: self)
scanningOperation.completionHandler = { (finished,cancelled) in scanningOperation.completionHandler = { (finished,cancelled) in
XCTAssert(finished) XCTAssert(finished)

View File

@ -23,14 +23,14 @@ class BlockStreamingTest: XCTestCase {
try? FileManager.default.removeItem(at: __dataDbURL()) try? FileManager.default.removeItem(at: __dataDbURL())
} }
func testExample() throws { func testStreamOperation() throws {
let expectation = XCTestExpectation(description: "blockstream expectation") let expectation = XCTestExpectation(description: "blockstream expectation")
let service = LightWalletGRPCService(host: "lightwalletd.testnet.electriccoin.co", let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067, port: 9067,
secure: true, secure: true,
singleCallTimeout: Int64.max, singleCallTimeout: 1000,
streamingCallTimeout: 1000) streamingCallTimeout: 100000)
let latestHeight = try service.latestBlockHeight() let latestHeight = try service.latestBlockHeight()
@ -55,43 +55,10 @@ class BlockStreamingTest: XCTestCase {
} }
func testStreamOperation() throws {
let expectation = XCTestExpectation(description: "blockstream expectation")
let service = LightWalletGRPCService(host: "lightwalletd.testnet.electriccoin.co",
port: 9067,
secure: true,
singleCallTimeout: 1000,
streamingCallTimeout: 1000)
let storage = try TestDbBuilder.inMemoryCompactBlockStorage()
let startHeight = try service.latestBlockHeight() - 100_000
let operation = CompactBlockStreamDownloadOperation(service: service,
storage: storage,
startHeight: startHeight,
progressDelegate: self)
operation.completionHandler = { (finished, cancelled) in
if cancelled {
XCTFail("operation cancelled")
}
expectation.fulfill()
}
operation.errorHandler = { error in
XCTFail("failed with error: \(error)")
expectation.fulfill()
}
queue.addOperation(operation)
wait(for: [expectation], timeout: 1000)
}
func testStreamOperationCancellation() throws { func testStreamOperationCancellation() throws {
let expectation = XCTestExpectation(description: "blockstream expectation") let expectation = XCTestExpectation(description: "blockstream expectation")
let service = LightWalletGRPCService(host: "lightwalletd.testnet.electriccoin.co", let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067, port: 9067,
secure: true, secure: true,
singleCallTimeout: 10000, singleCallTimeout: 10000,
@ -124,7 +91,7 @@ class BlockStreamingTest: XCTestCase {
func testStreamOperationTimeout() throws { func testStreamOperationTimeout() throws {
let expectation = XCTestExpectation(description: "blockstream expectation") let expectation = XCTestExpectation(description: "blockstream expectation")
let errorExpectation = XCTestExpectation(description: "blockstream error expectation") let errorExpectation = XCTestExpectation(description: "blockstream error expectation")
let service = LightWalletGRPCService(host: "lightwalletd.testnet.electriccoin.co", let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067, port: 9067,
secure: true, secure: true,
singleCallTimeout: 1000, singleCallTimeout: 1000,
@ -165,25 +132,18 @@ class BlockStreamingTest: XCTestCase {
let elapsed = now.distance(to: date) let elapsed = now.distance(to: date)
print("took \(elapsed) seconds") print("took \(elapsed) seconds")
} }
func testPerformanceExample() throws {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
func testBatchOperation() throws { func testBatchOperation() throws {
let expectation = XCTestExpectation(description: "blockbatch expectation") let expectation = XCTestExpectation(description: "blockbatch expectation")
let service = LightWalletGRPCService(host: "lightwalletd.testnet.electriccoin.co", let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067, port: 9067,
secure: true, secure: true,
singleCallTimeout: 300000, singleCallTimeout: 300000,
streamingCallTimeout: 10000) streamingCallTimeout: 10000)
let storage = try TestDbBuilder.diskCompactBlockStorage(at: __dataDbURL() ) let storage = try TestDbBuilder.diskCompactBlockStorage(at: __dataDbURL() )
let targetHeight = try service.latestBlockHeight() let targetHeight = try service.latestBlockHeight()
let startHeight = targetHeight - 100_000 let startHeight = targetHeight - 10_000
let operation = CompactBlockBatchDownloadOperation(service: service, let operation = CompactBlockBatchDownloadOperation(service: service,
storage: storage, storage: storage,
startHeight: startHeight, targetHeight: targetHeight, startHeight: startHeight, targetHeight: targetHeight,
@ -203,13 +163,13 @@ class BlockStreamingTest: XCTestCase {
queue.addOperation(operation) queue.addOperation(operation)
wait(for: [expectation], timeout: 300) wait(for: [expectation], timeout: 120)
} }
func testBatchOperationCancellation() throws { func testBatchOperationCancellation() throws {
let expectation = XCTestExpectation(description: "blockbatch expectation") let expectation = XCTestExpectation(description: "blockbatch expectation")
let service = LightWalletGRPCService(host: "lightwalletd.testnet.electriccoin.co", let service = LightWalletGRPCService(host: LightWalletEndpointBuilder.eccTestnet.host,
port: 9067, port: 9067,
secure: true, secure: true,
singleCallTimeout: 300000, singleCallTimeout: 300000,
@ -243,6 +203,6 @@ class BlockStreamingTest: XCTestCase {
extension BlockStreamingTest: CompactBlockProgressDelegate { extension BlockStreamingTest: CompactBlockProgressDelegate {
func progressUpdated(_ progress: CompactBlockProgress) { func progressUpdated(_ progress: CompactBlockProgress) {
// print("progressHeight: \(progress.progressHeight) startHeight: \(progress.startHeight), targetHeight: \(progress.targetHeight)") print("progressHeight: \(String(describing: progress.progressHeight)) startHeight: \(progress.progress), targetHeight: \(String(describing: progress.targetHeight))")
} }
} }

View File

@ -10,7 +10,7 @@ import XCTest
@testable import ZcashLightClientKit @testable import ZcashLightClientKit
class CompactBlockProcessorTests: XCTestCase { class CompactBlockProcessorTests: XCTestCase {
let processorConfig = CompactBlockProcessor.Configuration.standard let processorConfig = CompactBlockProcessor.Configuration.standard(for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.SAPLING_ACTIVATION_HEIGHT)
var processor: CompactBlockProcessor! var processor: CompactBlockProcessor!
var downloadStartedExpect: XCTestExpectation! var downloadStartedExpect: XCTestExpectation!
var updatedNotificationExpectation: XCTestExpectation! var updatedNotificationExpectation: XCTestExpectation!
@ -18,12 +18,26 @@ class CompactBlockProcessorTests: XCTestCase {
var startedScanningNotificationExpectation: XCTestExpectation! var startedScanningNotificationExpectation: XCTestExpectation!
var startedValidatingNotificationExpectation: XCTestExpectation! var startedValidatingNotificationExpectation: XCTestExpectation!
var idleNotificationExpectation: XCTestExpectation! var idleNotificationExpectation: XCTestExpectation!
let mockLatestHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 2000 let network = ZcashNetworkBuilder.network(for: .testnet)
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.SAPLING_ACTIVATION_HEIGHT + 2000
override func setUp() { override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class. // Put setup code here. This method is called before the invocation of each test method in the class.
logger = SampleLogger(logLevel: .debug)
let service = MockLightWalletService(latestBlockHeight: mockLatestHeight, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet))
let branchID = try ZcashRustBackend.consensusBranchIdFor(height: Int32(mockLatestHeight), networkType: network.networkType)
service.mockLightDInfo = LightdInfo.with({ info in
info.blockHeight = UInt64(mockLatestHeight)
info.branch = "asdf"
info.buildDate = "today"
info.buildUser = "testUser"
info.chainName = "test"
info.consensusBranchID = branchID.toString()
info.estimatedHeight = UInt64(mockLatestHeight)
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
})
let service = MockLightWalletService(latestBlockHeight: mockLatestHeight)
let storage = CompactBlockStorage.init(connectionProvider: SimpleConnectionProvider(path: processorConfig.cacheDb.absoluteString)) let storage = CompactBlockStorage.init(connectionProvider: SimpleConnectionProvider(path: processorConfig.cacheDb.absoluteString))
try! storage.createTable() try! storage.createTable()
@ -32,7 +46,7 @@ class CompactBlockProcessorTests: XCTestCase {
storage: storage, storage: storage,
backend: ZcashRustBackend.self, backend: ZcashRustBackend.self,
config: processorConfig) config: processorConfig)
try ZcashRustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: .testnet)
downloadStartedExpect = XCTestExpectation(description: self.description + " downloadStartedExpect") downloadStartedExpect = XCTestExpectation(description: self.description + " downloadStartedExpect")
stopNotificationExpectation = XCTestExpectation(description: self.description + " stopNotificationExpectation") stopNotificationExpectation = XCTestExpectation(description: self.description + " stopNotificationExpectation")
updatedNotificationExpectation = XCTestExpectation(description: self.description + " updatedNotificationExpectation") updatedNotificationExpectation = XCTestExpectation(description: self.description + " updatedNotificationExpectation")
@ -73,7 +87,7 @@ class CompactBlockProcessorTests: XCTestCase {
updatedNotificationExpectation.subscribe(to: Notification.Name.blockProcessorUpdated, object: processor) updatedNotificationExpectation.subscribe(to: Notification.Name.blockProcessorUpdated, object: processor)
startedValidatingNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedValidating, object: processor) startedValidatingNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedValidating, object: processor)
startedScanningNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedScanning, object: processor) startedScanningNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedScanning, object: processor)
idleNotificationExpectation.subscribe(to: Notification.Name.blockProcessorIdle, object: processor) idleNotificationExpectation.subscribe(to: Notification.Name.blockProcessorFinished, object: processor)
XCTAssertNoThrow(try processor.start()) XCTAssertNoThrow(try processor.start())
} }
@ -87,7 +101,7 @@ class CompactBlockProcessorTests: XCTestCase {
startedValidatingNotificationExpectation, startedValidatingNotificationExpectation,
startedScanningNotificationExpectation, startedScanningNotificationExpectation,
idleNotificationExpectation, idleNotificationExpectation,
], timeout: 260,enforceOrder: true) ], timeout: 30,enforceOrder: true)
} }
func testProgressNotifications() { func testProgressNotifications() {
@ -109,15 +123,15 @@ class CompactBlockProcessorTests: XCTestCase {
// test first range // test first range
var latestDownloadedHeight = processorConfig.walletBirthday // this can be either this or Wallet Birthday. var latestDownloadedHeight = processorConfig.walletBirthday // this can be either this or Wallet Birthday.
var latestBlockchainHeight = BlockHeight(ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 1000) var latestBlockchainHeight = BlockHeight(network.constants.SAPLING_ACTIVATION_HEIGHT + 1000)
var expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight, upper:latestBlockchainHeight)) var expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight, upper:latestBlockchainHeight))
XCTAssertEqual(expectedBatchRange, CompactBlockProcessor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight, walletBirthday: processorConfig.walletBirthday)) XCTAssertEqual(expectedBatchRange, CompactBlockProcessor.nextBatchBlockRange(latestHeight: latestBlockchainHeight, latestDownloadedHeight: latestDownloadedHeight, walletBirthday: processorConfig.walletBirthday))
// Test mid-range // Test mid-range
latestDownloadedHeight = BlockHeight(ZcashSDK.SAPLING_ACTIVATION_HEIGHT + ZcashSDK.DEFAULT_BATCH_SIZE) latestDownloadedHeight = BlockHeight(network.constants.SAPLING_ACTIVATION_HEIGHT + ZcashSDK.DEFAULT_BATCH_SIZE)
latestBlockchainHeight = BlockHeight(ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 1000) latestBlockchainHeight = BlockHeight(network.constants.SAPLING_ACTIVATION_HEIGHT + 1000)
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight)) expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))
@ -125,8 +139,8 @@ class CompactBlockProcessorTests: XCTestCase {
// Test last batch range // Test last batch range
latestDownloadedHeight = BlockHeight(ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 950) latestDownloadedHeight = BlockHeight(network.constants.SAPLING_ACTIVATION_HEIGHT + 950)
latestBlockchainHeight = BlockHeight(ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 1000) latestBlockchainHeight = BlockHeight(network.constants.SAPLING_ACTIVATION_HEIGHT + 1000)
expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight)) expectedBatchRange = CompactBlockRange(uncheckedBounds: (lower: latestDownloadedHeight + 1, upper: latestBlockchainHeight))

View File

@ -11,7 +11,7 @@ import XCTest
@testable import ZcashLightClientKit @testable import ZcashLightClientKit
class CompactBlockReorgTests: XCTestCase { class CompactBlockReorgTests: XCTestCase {
let processorConfig = CompactBlockProcessor.Configuration.standard let processorConfig = CompactBlockProcessor.Configuration.standard(for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: ZcashNetworkBuilder.network(for: .testnet).constants.SAPLING_ACTIVATION_HEIGHT)
var processor: CompactBlockProcessor! var processor: CompactBlockProcessor!
var downloadStartedExpect: XCTestExpectation! var downloadStartedExpect: XCTestExpectation!
var updatedNotificationExpectation: XCTestExpectation! var updatedNotificationExpectation: XCTestExpectation!
@ -20,19 +20,36 @@ class CompactBlockReorgTests: XCTestCase {
var startedValidatingNotificationExpectation: XCTestExpectation! var startedValidatingNotificationExpectation: XCTestExpectation!
var idleNotificationExpectation: XCTestExpectation! var idleNotificationExpectation: XCTestExpectation!
var reorgNotificationExpectation: XCTestExpectation! var reorgNotificationExpectation: XCTestExpectation!
let mockLatestHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 2000 let network = ZcashNetworkBuilder.network(for: .testnet)
let mockLatestHeight = ZcashNetworkBuilder.network(for: .testnet).constants.SAPLING_ACTIVATION_HEIGHT + 2000
override func setUp() { override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class. // Put setup code here. This method is called before the invocation of each test method in the class.
let service = MockLightWalletService(latestBlockHeight: mockLatestHeight) logger = SampleLogger(logLevel: .debug)
let service = MockLightWalletService(latestBlockHeight: mockLatestHeight, service: LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet))
let branchID = try ZcashRustBackend.consensusBranchIdFor(height: Int32(mockLatestHeight), networkType: network.networkType)
service.mockLightDInfo = LightdInfo.with({ info in
info.blockHeight = UInt64(mockLatestHeight)
info.branch = "asdf"
info.buildDate = "today"
info.buildUser = "testUser"
info.chainName = "test"
info.consensusBranchID = branchID.toString()
info.estimatedHeight = UInt64(mockLatestHeight)
info.saplingActivationHeight = UInt64(network.constants.SAPLING_ACTIVATION_HEIGHT)
})
try ZcashRustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: .testnet)
let storage = CompactBlockStorage.init(connectionProvider: SimpleConnectionProvider(path: processorConfig.cacheDb.absoluteString)) let storage = CompactBlockStorage.init(connectionProvider: SimpleConnectionProvider(path: processorConfig.cacheDb.absoluteString))
try! storage.createTable() try! storage.createTable()
let mockBackend = MockRustBackend.self let mockBackend = MockRustBackend.self
mockBackend.mockValidateCombinedChainFailAfterAttempts = 3 mockBackend.mockValidateCombinedChainFailAfterAttempts = 3
mockBackend.mockValidateCombinedChainKeepFailing = false mockBackend.mockValidateCombinedChainKeepFailing = false
mockBackend.mockValidateCombinedChainFailureHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 320 mockBackend.mockValidateCombinedChainFailureHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT + 320
processor = CompactBlockProcessor(service: service, processor = CompactBlockProcessor(service: service,
storage: storage, storage: storage,
@ -69,8 +86,8 @@ class CompactBlockReorgTests: XCTestCase {
XCTAssertNotNil(notification.userInfo) XCTAssertNotNil(notification.userInfo)
if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight, if let reorg = notification.userInfo?[CompactBlockProcessorNotificationKey.reorgHeight] as? BlockHeight,
let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight { let rewind = notification.userInfo?[CompactBlockProcessorNotificationKey.rewindHeight] as? BlockHeight {
XCTAssertTrue( reorg == 0 || reorg > ZcashSDK.SAPLING_ACTIVATION_HEIGHT) XCTAssertTrue( reorg == 0 || reorg > self.network.constants.SAPLING_ACTIVATION_HEIGHT)
XCTAssertTrue( rewind == 0 || rewind > ZcashSDK.SAPLING_ACTIVATION_HEIGHT) XCTAssertTrue( rewind == 0 || rewind > self.network.constants.SAPLING_ACTIVATION_HEIGHT)
XCTAssertTrue( rewind <= reorg ) XCTAssertTrue( rewind <= reorg )
reorgNotificationExpectation.fulfill() reorgNotificationExpectation.fulfill()
} else { } else {
@ -98,7 +115,7 @@ class CompactBlockReorgTests: XCTestCase {
updatedNotificationExpectation.subscribe(to: Notification.Name.blockProcessorUpdated, object: processor) updatedNotificationExpectation.subscribe(to: Notification.Name.blockProcessorUpdated, object: processor)
startedValidatingNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedValidating, object: processor) startedValidatingNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedValidating, object: processor)
startedScanningNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedScanning, object: processor) startedScanningNotificationExpectation.subscribe(to: Notification.Name.blockProcessorStartedScanning, object: processor)
idleNotificationExpectation.subscribe(to: Notification.Name.blockProcessorIdle, object: processor) idleNotificationExpectation.subscribe(to: Notification.Name.blockProcessorFinished, object: processor)
reorgNotificationExpectation.subscribe(to: Notification.Name.blockProcessorHandledReOrg, object: processor) reorgNotificationExpectation.subscribe(to: Notification.Name.blockProcessorHandledReOrg, object: processor)
XCTAssertNoThrow(try processor.start()) XCTAssertNoThrow(try processor.start())

View File

@ -13,13 +13,14 @@ class CompactBlockStorageTests: XCTestCase {
var compactBlockDao: CompactBlockRepository = try! TestDbBuilder.inMemoryCompactBlockStorage() var compactBlockDao: CompactBlockRepository = try! TestDbBuilder.inMemoryCompactBlockStorage()
let network = ZcashNetworkBuilder.network(for: .testnet)
func testEmptyStorage() { func testEmptyStorage() {
XCTAssertEqual(try! compactBlockDao.latestHeight(), BlockHeight.empty()) XCTAssertEqual(try! compactBlockDao.latestHeight(), BlockHeight.empty())
} }
func testStoreThousandBlocks() { func testStoreThousandBlocks() {
let initialHeight = try! compactBlockDao.latestHeight() let initialHeight = try! compactBlockDao.latestHeight()
let startHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT let startHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT
let blockCount = Int(1_000) let blockCount = Int(1_000)
let finalHeight = startHeight + blockCount let finalHeight = startHeight + blockCount
@ -62,7 +63,7 @@ class CompactBlockStorageTests: XCTestCase {
func testRewindTo() { func testRewindTo() {
let startHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT let startHeight = self.network.constants.SAPLING_ACTIVATION_HEIGHT
let blockCount = Int(1_000) let blockCount = Int(1_000)
let finalHeight = startHeight + blockCount let finalHeight = startHeight + blockCount

View File

@ -22,15 +22,20 @@ class DarksideSanityCheckTests: XCTestCase {
var sentTransactionExpectation = XCTestExpectation(description: "sent") var sentTransactionExpectation = XCTestExpectation(description: "sent")
var expectedReorgHeight: BlockHeight = 665188 var expectedReorgHeight: BlockHeight = 665188
var expectedRewindHeight: BlockHeight = 665188 var expectedRewindHeight: BlockHeight = 665188
var network = DarksideWalletDNetwork()
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg") var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
let branchID = "2bb40e60"
let chainName = "main"
override func setUpWithError() throws { override func setUpWithError() throws {
coordinator = try TestCoordinator( coordinator = try TestCoordinator(
seed: seedPhrase, seed: seedPhrase,
walletBirthday: birthday, walletBirthday: birthday,
channelProvider: ChannelProvider() channelProvider: ChannelProvider(),
network: network
) )
try coordinator.reset(saplingActivation: birthday, branchID: "e9ff75a6", chainName: "main") try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
try coordinator.resetBlocks(dataset: .default) try coordinator.resetBlocks(dataset: .default)
} }

View File

@ -12,7 +12,7 @@ import SQLite
class DownloadOperationTests: XCTestCase { class DownloadOperationTests: XCTestCase {
var operationQueue = OperationQueue() var operationQueue = OperationQueue()
var network = ZcashNetworkBuilder.network(for: .testnet)
override func tearDown() { override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class. // Put teardown code here. This method is called after the invocation of each test method in the class.
operationQueue.cancelAllOperations() operationQueue.cancelAllOperations()
@ -21,11 +21,12 @@ class DownloadOperationTests: XCTestCase {
func testSingleOperation() { func testSingleOperation() {
let expect = XCTestExpectation(description: self.description) let expect = XCTestExpectation(description: self.description)
let service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default) let service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet)
let storage = try! TestDbBuilder.inMemoryCompactBlockStorage() let storage = try! TestDbBuilder.inMemoryCompactBlockStorage()
let downloader = CompactBlockDownloader(service: service, storage: storage) let downloader = CompactBlockDownloader(service: service, storage: storage)
let blockCount = 100 let blockCount = 100
let range = ZcashSDK.SAPLING_ACTIVATION_HEIGHT ... ZcashSDK.SAPLING_ACTIVATION_HEIGHT + blockCount let activationHeight = network.constants.SAPLING_ACTIVATION_HEIGHT
let range = activationHeight ... activationHeight + blockCount
let downloadOperation = CompactBlockDownloadOperation(downloader: downloader, range: range) let downloadOperation = CompactBlockDownloadOperation(downloader: downloader, range: range)
downloadOperation.completionHandler = { (finished, cancelled) in downloadOperation.completionHandler = { (finished, cancelled) in

View File

@ -13,10 +13,11 @@ class LightWalletServiceTests: XCTestCase {
var service: LightWalletService! var service: LightWalletService!
var channel: Channel! var channel: Channel!
let network: ZcashNetwork = ZcashNetworkBuilder.network(for: .testnet)
override func setUp() { override func setUp() {
// Put setup code here. This method is called before the invocation of each test method in the class. // Put setup code here. This method is called before the invocation of each test method in the class.
channel = ChannelProvider().channel() channel = ChannelProvider().channel()
service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default) service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.eccTestnet)
} }
override func tearDown() { override func tearDown() {
@ -39,8 +40,8 @@ class LightWalletServiceTests: XCTestCase {
func testHundredBlocks() { func testHundredBlocks() {
let expect = XCTestExpectation(description: self.description) let expect = XCTestExpectation(description: self.description)
let count = 99 let count = 99
let lowerRange: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT let lowerRange: BlockHeight = network.constants.SAPLING_ACTIVATION_HEIGHT
let upperRange: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT + count let upperRange: BlockHeight = network.constants.SAPLING_ACTIVATION_HEIGHT + count
let blockRange = lowerRange ... upperRange let blockRange = lowerRange ... upperRange
service.blockRange(blockRange) { (result) in service.blockRange(blockRange) { (result) in
@ -60,8 +61,8 @@ class LightWalletServiceTests: XCTestCase {
} }
func testSyncBlockRange() { func testSyncBlockRange() {
let lowerRange: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT let lowerRange: BlockHeight = network.constants.SAPLING_ACTIVATION_HEIGHT
let upperRange: BlockHeight = ZcashSDK.SAPLING_ACTIVATION_HEIGHT + 99 let upperRange: BlockHeight = network.constants.SAPLING_ACTIVATION_HEIGHT + 99
let blockRange = lowerRange ... upperRange let blockRange = lowerRange ... upperRange
do { do {
@ -80,7 +81,7 @@ class LightWalletServiceTests: XCTestCase {
case .failure(let e): case .failure(let e):
XCTFail("error: \(e)") XCTFail("error: \(e)")
case .success(let height): case .success(let height):
XCTAssertTrue(height > ZcashSDK.SAPLING_ACTIVATION_HEIGHT) XCTAssertTrue(height > self.network.constants.SAPLING_ACTIVATION_HEIGHT)
} }
} }

View File

@ -19,7 +19,8 @@ class NetworkUpgradeTests: XCTestCase {
let branchID = "2bb40e60" let branchID = "2bb40e60"
let chainName = "main" let chainName = "main"
var coordinator: TestCoordinator! var coordinator: TestCoordinator!
var network = ZcashNetworkBuilder.network(for: .testnet)
override func setUpWithError() throws { override func setUpWithError() throws {
// coordinator = try TestCoordinator( // coordinator = try TestCoordinator(
@ -28,7 +29,7 @@ class NetworkUpgradeTests: XCTestCase {
// walletBirthday: birthday, // walletBirthday: birthday,
// channelProvider: ChannelProvider() // channelProvider: ChannelProvider()
// ) // )
try coordinator.reset(saplingActivation: birthday, branchID: "e9ff75a6", chainName: "main") try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
} }
override func tearDownWithError() throws { override func tearDownWithError() throws {
@ -59,7 +60,7 @@ class NetworkUpgradeTests: XCTestCase {
wait(for: [firstSyncExpectation], timeout: 120) wait(for: [firstSyncExpectation], timeout: 120)
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
guard verifiedBalance > ZcashSDK.MINERS_FEE_ZATOSHI else { guard verifiedBalance > network.constants.defaultFee(for: activationHeight) else {
XCTFail("not enough balance to continue test") XCTFail("not enough balance to continue test")
return return
} }
@ -206,7 +207,7 @@ class NetworkUpgradeTests: XCTestCase {
wait(for: [firstSyncExpectation], timeout: 120) wait(for: [firstSyncExpectation], timeout: 120)
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
XCTAssertTrue(verifiedBalance > ZcashSDK.MINERS_FEE_ZATOSHI) XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: activationHeight))
@ -296,7 +297,7 @@ class NetworkUpgradeTests: XCTestCase {
wait(for: [firstSyncExpectation], timeout: 120) wait(for: [firstSyncExpectation], timeout: 120)
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
guard verifiedBalance > ZcashSDK.MINERS_FEE_ZATOSHI else { guard verifiedBalance > network.constants.defaultFee(for: activationHeight) else {
XCTFail("balance is not enough to continue with this test") XCTFail("balance is not enough to continue with this test")
return return
} }
@ -403,7 +404,7 @@ class NetworkUpgradeTests: XCTestCase {
var p: PendingTransactionEntity? = nil var p: PendingTransactionEntity? = nil
// spend all the funds // spend all the funds
let spendAmount: Int64 = postActivationBalance - Int64(ZcashSDK.MINERS_FEE_ZATOSHI) let spendAmount: Int64 = postActivationBalance - Int64(network.constants.defaultFee(for: activationHeight))
/* /*
send transaction to recipient address send transaction to recipient address

View File

@ -8,18 +8,18 @@
import XCTest import XCTest
@testable import ZcashLightClientKit @testable import ZcashLightClientKit
class NullBytesTests: XCTestCase { class NullBytesTests: XCTestCase {
let networkType = NetworkType.mainnet
func testZaddrNullBytes() throws { func testZaddrNullBytes() throws {
let validZaddr = "zs1gqtfu59z20s9t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp" // this is a valid zAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/ let validZaddr = "zs1gqtfu59z20s9t20mxlxj86zpw6p69l0ev98uxrmlykf2nchj2dw8ny5e0l22kwmld2afc37gkfp" // this is a valid zAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/
let ZaddrWithNullBytes = "\(validZaddr)\0something else that makes the address invalid" let ZaddrWithNullBytes = "\(validZaddr)\0something else that makes the address invalid"
XCTAssertFalse(try ZcashRustBackend.isValidShieldedAddress(ZaddrWithNullBytes)) XCTAssertFalse(try ZcashRustBackend.isValidShieldedAddress(ZaddrWithNullBytes, networkType: networkType))
} }
func testTaddrNullBytes() throws { func testTaddrNullBytes() throws {
let validTAddr = "t1J5pTRzJi7j8Xw9VJTrPxPEkaigr69gKVT" // this is a valid tAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/ let validTAddr = "t1J5pTRzJi7j8Xw9VJTrPxPEkaigr69gKVT" // this is a valid tAddr. if you send ZEC to it, you will be contributing to Human Rights Foundation. see more ways to help at https://paywithz.cash/
let TaddrWithNullBytes = "\(validTAddr)\0fasdfasdf" let TaddrWithNullBytes = "\(validTAddr)\0fasdfasdf"
XCTAssertFalse(try ZcashRustBackend.isValidTransparentAddress(TaddrWithNullBytes)) XCTAssertFalse(try ZcashRustBackend.isValidTransparentAddress(TaddrWithNullBytes, networkType: networkType))
} }
func testInitAccountTableNullBytes() throws { func testInitAccountTableNullBytes() throws {
@ -30,7 +30,7 @@ class NullBytesTests: XCTestCase {
let wrongTree = "0161f2ff97ff6ac6a90f9bce76c11710460f4944d8695aecc7dc99e34cad0131040011015325b185e23e82562db27817be996ffade9597181244f67efc40561aeb9dde1101daeffadc9e38f755bcb55a847a1278518a0ba4a2ef33b2fe01bbb3eb242ab0070000000000011c51f9077e3f7e28e8e337eaf4bb99b41acbc853a37dcc1e172467a1c919fe4100010bb1f55481b2268ef31997dc0fb6b48a530bc17870220f156d832326c433eb0a010b3768d3bf7868a67823e022f49be67982d0588e7041c498a756024\0750065a4a0001a9e1bf4bccb48b14b544e770f21d48f2d3ad8d6ca54eccc92f60634e3078eb48013a1f7fb005388ac6f04099b647ed85d8b025d8ae4b178c2376b473b121b8c052000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260" let wrongTree = "0161f2ff97ff6ac6a90f9bce76c11710460f4944d8695aecc7dc99e34cad0131040011015325b185e23e82562db27817be996ffade9597181244f67efc40561aeb9dde1101daeffadc9e38f755bcb55a847a1278518a0ba4a2ef33b2fe01bbb3eb242ab0070000000000011c51f9077e3f7e28e8e337eaf4bb99b41acbc853a37dcc1e172467a1c919fe4100010bb1f55481b2268ef31997dc0fb6b48a530bc17870220f156d832326c433eb0a010b3768d3bf7868a67823e022f49be67982d0588e7041c498a756024\0750065a4a0001a9e1bf4bccb48b14b544e770f21d48f2d3ad8d6ca54eccc92f60634e3078eb48013a1f7fb005388ac6f04099b647ed85d8b025d8ae4b178c2376b473b121b8c052000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
let goodTree = "0161f2ff97ff6ac6a90f9bce76c11710460f4944d8695aecc7dc99e34cad0131040011015325b185e23e82562db27817be996ffade9597181244f67efc40561aeb9dde1101daeffadc9e38f755bcb55a847a1278518a0ba4a2ef33b2fe01bbb3eb242ab0070000000000011c51f9077e3f7e28e8e337eaf4bb99b41acbc853a37dcc1e172467a1c919fe4100010bb1f55481b2268ef31997dc0fb6b48a530bc17870220f156d832326c433eb0a010b3768d3bf7868a67823e022f49be67982d0588e7041c498a756024750065a4a0001a9e1bf4bccb48b14b544e770f21d48f2d3ad8d6ca54eccc92f60634e3078eb48013a1f7fb005388ac6f04099b647ed85d8b025d8ae4b178c2376b473b121b8c052000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260" let goodTree = "0161f2ff97ff6ac6a90f9bce76c11710460f4944d8695aecc7dc99e34cad0131040011015325b185e23e82562db27817be996ffade9597181244f67efc40561aeb9dde1101daeffadc9e38f755bcb55a847a1278518a0ba4a2ef33b2fe01bbb3eb242ab0070000000000011c51f9077e3f7e28e8e337eaf4bb99b41acbc853a37dcc1e172467a1c919fe4100010bb1f55481b2268ef31997dc0fb6b48a530bc17870220f156d832326c433eb0a010b3768d3bf7868a67823e022f49be67982d0588e7041c498a756024750065a4a0001a9e1bf4bccb48b14b544e770f21d48f2d3ad8d6ca54eccc92f60634e3078eb48013a1f7fb005388ac6f04099b647ed85d8b025d8ae4b178c2376b473b121b8c052000001d2ea556f49fb934dc76f087935a5c07788000b4e3aae24883adfec51b5f4d260"
XCTAssertThrowsError(try ZcashRustBackend.initBlocksTable(dbData: __dataDbURL(), height: height , hash: wrongHash, time: time, saplingTree: goodTree), "InitBlocksTable with Null bytes on hash string should have failed") { (error) in XCTAssertThrowsError(try ZcashRustBackend.initBlocksTable(dbData: __dataDbURL(), height: height , hash: wrongHash, time: time, saplingTree: goodTree, networkType: networkType), "InitBlocksTable with Null bytes on hash string should have failed") { (error) in
guard let rustError = error as? RustWeldingError else { guard let rustError = error as? RustWeldingError else {
XCTFail("Expected RustWeldingError") XCTFail("Expected RustWeldingError")
@ -45,7 +45,7 @@ class NullBytesTests: XCTestCase {
} }
} }
XCTAssertThrowsError(try ZcashRustBackend.initBlocksTable(dbData: __dataDbURL(), height: height , hash: goodHash, time: time, saplingTree: wrongTree), "InitBlocksTable with Null bytes on saplingTree string should have failed") { (error) in XCTAssertThrowsError(try ZcashRustBackend.initBlocksTable(dbData: __dataDbURL(), height: height , hash: goodHash, time: time, saplingTree: wrongTree, networkType: networkType), "InitBlocksTable with Null bytes on saplingTree string should have failed") { (error) in
guard let rustError = error as? RustWeldingError else { guard let rustError = error as? RustWeldingError else {
XCTFail("Expected RustWeldingError") XCTFail("Expected RustWeldingError")
@ -66,7 +66,7 @@ class NullBytesTests: XCTestCase {
let goodSpendingKeys = "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mquy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv" let goodSpendingKeys = "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mquy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv"
XCTAssertThrowsError(try ZcashRustBackend.deriveExtendedFullViewingKey(wrongSpendingKeys),"Should have thrown an error but didn't! this is dangerous!") { (error) in XCTAssertThrowsError(try ZcashRustBackend.deriveExtendedFullViewingKey(wrongSpendingKeys, networkType: networkType),"Should have thrown an error but didn't! this is dangerous!") { (error) in
guard let rustError = error as? RustWeldingError else { guard let rustError = error as? RustWeldingError else {
XCTFail("Expected RustWeldingError") XCTFail("Expected RustWeldingError")
@ -81,7 +81,7 @@ class NullBytesTests: XCTestCase {
} }
} }
XCTAssertNoThrow(try ZcashRustBackend.deriveExtendedFullViewingKey(goodSpendingKeys)) XCTAssertNoThrow(try ZcashRustBackend.deriveExtendedFullViewingKey(goodSpendingKeys, networkType: networkType))
} }

View File

@ -13,7 +13,7 @@ class PagedTransactionRepositoryTests: XCTestCase {
var transactionRepository: TransactionRepository! var transactionRepository: TransactionRepository!
override func setUp() { override func setUp() {
transactionRepository = MockTransactionRepository(unminedCount: 5, receivedCount: 150, sentCount: 100) transactionRepository = MockTransactionRepository(unminedCount: 5, receivedCount: 150, sentCount: 100, network: ZcashNetworkBuilder.network(for: .testnet))
pagedTransactionRepository = PagedTransactionDAO(repository: transactionRepository) pagedTransactionRepository = PagedTransactionDAO(repository: transactionRepository)
} }

View File

@ -23,12 +23,14 @@ class PendingTransactionUpdatesTest: XCTestCase {
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg") var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
let branchID = "2bb40e60" let branchID = "2bb40e60"
let chainName = "main" let chainName = "main"
let network = DarksideWalletDNetwork()
override func setUpWithError() throws { override func setUpWithError() throws {
coordinator = try TestCoordinator( coordinator = try TestCoordinator(
seed: seedPhrase, seed: seedPhrase,
walletBirthday: birthday, walletBirthday: birthday,
channelProvider: ChannelProvider() channelProvider: ChannelProvider(),
network: network
) )
try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main") try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main")
} }

View File

@ -22,25 +22,29 @@ import XCTest
class ReOrgTests: XCTestCase { class ReOrgTests: XCTestCase {
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment? var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment?
let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment let testRecipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a" //TODO: Parameterize this from environment
let sendAmount: Int64 = 1000 let sendAmount: Int64 = 1000
var birthday: BlockHeight = 663150 var birthday: BlockHeight = 663150
let defaultLatestHeight: BlockHeight = 663175 let defaultLatestHeight: BlockHeight = 663175
var coordinator: TestCoordinator! var coordinator: TestCoordinator!
var syncedExpectation = XCTestExpectation(description: "synced") var syncedExpectation = XCTestExpectation(description: "synced")
var sentTransactionExpectation = XCTestExpectation(description: "sent") var sentTransactionExpectation = XCTestExpectation(description: "sent")
var expectedReorgHeight: BlockHeight = 665188 var expectedReorgHeight: BlockHeight = 665188
var expectedRewindHeight: BlockHeight = 665188 var expectedRewindHeight: BlockHeight = 665188
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg") let network = DarksideWalletDNetwork()
override func setUpWithError() throws { let branchID = "2bb40e60"
let chainName = "main"
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
override func setUpWithError() throws {
NotificationCenter.default.addObserver(self, selector: #selector(handleReOrgNotification(_:)), name: Notification.Name.blockProcessorHandledReOrg, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handleReOrgNotification(_:)), name: Notification.Name.blockProcessorHandledReOrg, object: nil)
coordinator = try TestCoordinator( coordinator = try TestCoordinator(
seed: seedPhrase, seed: seedPhrase,
walletBirthday: birthday, walletBirthday: birthday,
channelProvider: ChannelProvider() channelProvider: ChannelProvider(),
network: network
) )
try coordinator.reset(saplingActivation: birthday, branchID: "e9ff75a6", chainName: "main") try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
try coordinator.resetBlocks(dataset: .default) try coordinator.resetBlocks(dataset: .default)
} }
@ -75,7 +79,7 @@ class ReOrgTests: XCTestCase {
let mockLatestHeight = BlockHeight(663200) let mockLatestHeight = BlockHeight(663200)
let targetLatestHeight = BlockHeight(663202) let targetLatestHeight = BlockHeight(663202)
let reOrgHeight = BlockHeight(663195) let reOrgHeight = BlockHeight(663195)
let walletBirthday = WalletBirthday.birthday(with: 663150).height let walletBirthday = WalletBirthday.birthday(with: 663150, network: network).height
try basicReOrgTest(baseDataset: .beforeReOrg, try basicReOrgTest(baseDataset: .beforeReOrg,
reorgDataset: .afterSmallReorg, reorgDataset: .afterSmallReorg,
@ -89,7 +93,7 @@ class ReOrgTests: XCTestCase {
let mockLatestHeight = BlockHeight(663200) let mockLatestHeight = BlockHeight(663200)
let targetLatestHeight = BlockHeight(663250) let targetLatestHeight = BlockHeight(663250)
let reOrgHeight = BlockHeight(663180) let reOrgHeight = BlockHeight(663180)
let walletBirthday = WalletBirthday.birthday(with: BlockHeight(663150)).height let walletBirthday = WalletBirthday.birthday(with: BlockHeight(663150), network: network).height
try basicReOrgTest(baseDataset: .beforeReOrg, try basicReOrgTest(baseDataset: .beforeReOrg,
reorgDataset: .afterLargeReorg, reorgDataset: .afterLargeReorg,
@ -107,7 +111,7 @@ class ReOrgTests: XCTestCase {
targetHeight: BlockHeight) throws { targetHeight: BlockHeight) throws {
do { do {
try coordinator.reset(saplingActivation: birthday, branchID: "e9ff75a6", chainName: "main") try coordinator.reset(saplingActivation: birthday, branchID: branchID, chainName: chainName)
try coordinator.resetBlocks(dataset: .predefined(dataset: .beforeReOrg)) try coordinator.resetBlocks(dataset: .predefined(dataset: .beforeReOrg))
try coordinator.applyStaged(blockheight: firstLatestHeight) try coordinator.applyStaged(blockheight: firstLatestHeight)
} catch { } catch {

View File

@ -23,12 +23,14 @@ class RewindRescanTests: XCTestCase {
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg") var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
let branchID = "2bb40e60" let branchID = "2bb40e60"
let chainName = "main" let chainName = "main"
var network = ZcashNetworkBuilder.network(for: .mainnet)
override func setUpWithError() throws { override func setUpWithError() throws {
coordinator = try TestCoordinator( coordinator = try TestCoordinator(
seed: seedPhrase, seed: seedPhrase,
walletBirthday: birthday, walletBirthday: birthday,
channelProvider: ChannelProvider() channelProvider: ChannelProvider(),
network: network
) )
try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main") try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main")
} }
@ -68,7 +70,7 @@ class RewindRescanTests: XCTestCase {
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let totalBalance = coordinator.synchronizer.initializer.getBalance() let totalBalance = coordinator.synchronizer.initializer.getBalance()
// 2 check that there are no unconfirmed funds // 2 check that there are no unconfirmed funds
XCTAssertTrue(verifiedBalance > ZcashSDK.defaultFee()) XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: defaultLatestHeight))
XCTAssertEqual(verifiedBalance, totalBalance) XCTAssertEqual(verifiedBalance, totalBalance)
// rewind to birthday // rewind to birthday
@ -114,12 +116,12 @@ class RewindRescanTests: XCTestCase {
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let totalBalance = coordinator.synchronizer.initializer.getBalance() let totalBalance = coordinator.synchronizer.initializer.getBalance()
// 2 check that there are no unconfirmed funds // 2 check that there are no unconfirmed funds
XCTAssertTrue(verifiedBalance > ZcashSDK.defaultFee()) XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: defaultLatestHeight))
XCTAssertEqual(verifiedBalance, totalBalance) XCTAssertEqual(verifiedBalance, totalBalance)
// rewind to birthday // rewind to birthday
let targetHeight: BlockHeight = newChaintTip - 8000 let targetHeight: BlockHeight = newChaintTip - 8000
let rewindHeight = ZcashRustBackend.getNearestRewindHeight(dbData: coordinator.databases.dataDB, height: Int32(targetHeight)) let rewindHeight = ZcashRustBackend.getNearestRewindHeight(dbData: coordinator.databases.dataDB, height: Int32(targetHeight), networkType: network.networkType)
try coordinator.synchronizer.rewind(.height(blockheight: targetHeight)) try coordinator.synchronizer.rewind(.height(blockheight: targetHeight))
@ -179,7 +181,7 @@ class RewindRescanTests: XCTestCase {
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let totalBalance = coordinator.synchronizer.initializer.getBalance() let totalBalance = coordinator.synchronizer.initializer.getBalance()
// 2 check that there are no unconfirmed funds // 2 check that there are no unconfirmed funds
XCTAssertTrue(verifiedBalance > ZcashSDK.defaultFee()) XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: defaultLatestHeight))
XCTAssertEqual(verifiedBalance, totalBalance) XCTAssertEqual(verifiedBalance, totalBalance)
// rewind to transaction // rewind to transaction
@ -192,7 +194,7 @@ class RewindRescanTests: XCTestCase {
// assert that after the new height is // assert that after the new height is
XCTAssertEqual(try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(),transaction.transactionEntity.anchor) XCTAssertEqual(try coordinator.synchronizer.initializer.transactionRepository.lastScannedHeight(),transaction.transactionEntity.anchor(network: network))
let secondScanExpectation = XCTestExpectation(description: "rescan") let secondScanExpectation = XCTestExpectation(description: "rescan")
@ -232,10 +234,10 @@ class RewindRescanTests: XCTestCase {
let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance() let verifiedBalance = coordinator.synchronizer.initializer.getVerifiedBalance()
let totalBalance = coordinator.synchronizer.initializer.getBalance() let totalBalance = coordinator.synchronizer.initializer.getBalance()
XCTAssertTrue(verifiedBalance > ZcashSDK.defaultFee()) XCTAssertTrue(verifiedBalance > network.constants.defaultFee(for: defaultLatestHeight))
XCTAssertEqual(verifiedBalance, totalBalance) XCTAssertEqual(verifiedBalance, totalBalance)
let maxBalance = verifiedBalance - Int64(ZcashSDK.defaultFee()) let maxBalance = verifiedBalance - Int64(network.constants.defaultFee(for: defaultLatestHeight))
// 3 create a transaction for the max amount possible // 3 create a transaction for the max amount possible
// 4 send the transaction // 4 send the transaction

View File

@ -23,13 +23,15 @@ class SychronizerDarksideTests: XCTestCase {
var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg") var reorgExpectation: XCTestExpectation = XCTestExpectation(description: "reorg")
let branchID = "2bb40e60" let branchID = "2bb40e60"
let chainName = "main" let chainName = "main"
let network = DarksideWalletDNetwork()
var foundTransactions = [ConfirmedTransactionEntity]() var foundTransactions = [ConfirmedTransactionEntity]()
override func setUpWithError() throws { override func setUpWithError() throws {
coordinator = try TestCoordinator( coordinator = try TestCoordinator(
seed: seedPhrase, seed: seedPhrase,
walletBirthday: birthday, walletBirthday: birthday,
channelProvider: ChannelProvider() channelProvider: ChannelProvider(),
network: network
) )
try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main") try coordinator.reset(saplingActivation: 663150, branchID: "e9ff75a6", chainName: "main")
} }

View File

@ -43,32 +43,36 @@ class TestCoordinator {
var service: DarksideWalletService var service: DarksideWalletService
var spendingKeys: [String]? var spendingKeys: [String]?
var databases: TemporaryTestDatabases var databases: TemporaryTestDatabases
let network: ZcashNetwork
convenience init(seed: String, convenience init(seed: String,
walletBirthday: BlockHeight, walletBirthday: BlockHeight,
channelProvider: ChannelProvider) throws { channelProvider: ChannelProvider,
guard let spendingKey = try DerivationTool.default.deriveSpendingKeys( network: ZcashNetwork) throws {
let derivationTool = DerivationTool(networkType: network.networkType)
guard let spendingKey = try derivationTool.deriveSpendingKeys(
seed: TestSeed().seed(), seed: TestSeed().seed(),
numberOfAccounts: 1).first else { numberOfAccounts: 1).first else {
throw CoordinatorError.builderError throw CoordinatorError.builderError
} }
guard let uvk = try DerivationTool.default.deriveUnifiedViewingKeysFromSeed(TestSeed().seed(), numberOfAccounts: 1).first else { guard let uvk = try derivationTool.deriveUnifiedViewingKeysFromSeed(TestSeed().seed(), numberOfAccounts: 1).first else {
throw CoordinatorError.builderError throw CoordinatorError.builderError
} }
try self.init(spendingKey: spendingKey, unifiedViewingKey: uvk, walletBirthday: walletBirthday, channelProvider: channelProvider) try self.init(spendingKey: spendingKey, unifiedViewingKey: uvk, walletBirthday: walletBirthday, channelProvider: channelProvider, network: network)
} }
required init( required init(
spendingKey: String, spendingKey: String,
unifiedViewingKey: UnifiedViewingKey, unifiedViewingKey: UnifiedViewingKey,
walletBirthday: BlockHeight, walletBirthday: BlockHeight,
channelProvider: ChannelProvider) throws { channelProvider: ChannelProvider,
network: ZcashNetwork) throws {
self.spendingKey = spendingKey self.spendingKey = spendingKey
self.birthday = walletBirthday self.birthday = walletBirthday
self.channelProvider = channelProvider self.channelProvider = channelProvider
self.databases = TemporaryDbBuilder.build() self.databases = TemporaryDbBuilder.build()
self.network = network
self.service = DarksideWalletService(service: LightWalletGRPCService(host: Constants.address, port: 9067, secure: false, singleCallTimeout: 10000, streamingCallTimeout: 1000000)) self.service = DarksideWalletService(service: LightWalletGRPCService(host: Constants.address, port: 9067, secure: false, singleCallTimeout: 10000, streamingCallTimeout: 1000000))
let storage = CompactBlockStorage(url: databases.cacheDB, readonly: false) let storage = CompactBlockStorage(url: databases.cacheDB, readonly: false)
try storage.createTable() try storage.createTable()
@ -89,7 +93,8 @@ class TestCoordinator {
outputParamsURL: try __outputParamsURL(), outputParamsURL: try __outputParamsURL(),
spendingKey: spendingKey, spendingKey: spendingKey,
unifiedViewingKey: unifiedViewingKey, unifiedViewingKey: unifiedViewingKey,
walletBirthday: WalletBirthday.birthday(with: birthday), walletBirthday: WalletBirthday.birthday(with: birthday, network: network),
network: network,
loggerProxy: SampleLogger(logLevel: .debug)) loggerProxy: SampleLogger(logLevel: .debug))
self.synchronizer = buildResult.synchronizer self.synchronizer = buildResult.synchronizer
@ -210,7 +215,8 @@ extension TestCoordinator {
maxBackoffInterval: config.maxBackoffInterval, maxBackoffInterval: config.maxBackoffInterval,
rewindDistance: config.rewindDistance, rewindDistance: config.rewindDistance,
walletBirthday: config.walletBirthday, walletBirthday: config.walletBirthday,
saplingActivation: config.saplingActivation) saplingActivation: config.saplingActivation,
network: config.network)
try service.reset(saplingActivation: saplingActivation, branchID: branchID, chainName: chainName) try service.reset(saplingActivation: saplingActivation, branchID: branchID, chainName: chainName)
} }
@ -254,11 +260,13 @@ class TestSynchronizerBuilder {
spendingKey: String, spendingKey: String,
unifiedViewingKey: UnifiedViewingKey, unifiedViewingKey: UnifiedViewingKey,
walletBirthday: WalletBirthday, walletBirthday: WalletBirthday,
network: ZcashNetwork,
loggerProxy: Logger? = nil loggerProxy: Logger? = nil
) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) { ) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) {
let initializer = Initializer( let initializer = Initializer(
rustBackend: rustBackend, rustBackend: rustBackend,
lowerBoundHeight: lowerBoundHeight, lowerBoundHeight: lowerBoundHeight,
network: network,
cacheDbURL: cacheDbURL, cacheDbURL: cacheDbURL,
dataDbURL: dataDbURL, dataDbURL: dataDbURL,
pendingDbURL: pendingDbURL, pendingDbURL: pendingDbURL,
@ -281,7 +289,8 @@ class TestSynchronizerBuilder {
maxBackoffInterval: ZcashSDK.DEFAULT_MAX_BACKOFF_INTERVAL, maxBackoffInterval: ZcashSDK.DEFAULT_MAX_BACKOFF_INTERVAL,
rewindDistance: ZcashSDK.DEFAULT_REWIND_DISTANCE, rewindDistance: ZcashSDK.DEFAULT_REWIND_DISTANCE,
walletBirthday: walletBirthday.height, walletBirthday: walletBirthday.height,
saplingActivation: lowerBoundHeight) saplingActivation: lowerBoundHeight,
network: network)
let processor = CompactBlockProcessor(service: service, let processor = CompactBlockProcessor(service: service,
storage: storage, storage: storage,
@ -318,13 +327,14 @@ class TestSynchronizerBuilder {
outputParamsURL: URL, outputParamsURL: URL,
seedBytes: [UInt8], seedBytes: [UInt8],
walletBirthday: WalletBirthday, walletBirthday: WalletBirthday,
network: ZcashNetwork,
loggerProxy: Logger? = nil loggerProxy: Logger? = nil
) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) { ) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) {
guard let spendingKey = try DerivationTool().deriveSpendingKeys(seed: seedBytes, numberOfAccounts: 1).first else { guard let spendingKey = try DerivationTool(networkType: network.networkType).deriveSpendingKeys(seed: seedBytes, numberOfAccounts: 1).first else {
throw TestCoordinator.CoordinatorError.builderError throw TestCoordinator.CoordinatorError.builderError
} }
guard let uvk = try DerivationTool().deriveUnifiedViewingKeysFromSeed(seedBytes, numberOfAccounts: 1).first else { guard let uvk = try DerivationTool(networkType: network.networkType).deriveUnifiedViewingKeysFromSeed(seedBytes, numberOfAccounts: 1).first else {
throw TestCoordinator.CoordinatorError.builderError throw TestCoordinator.CoordinatorError.builderError
} }
return try build(rustBackend: rustBackend, return try build(rustBackend: rustBackend,
@ -341,7 +351,8 @@ class TestSynchronizerBuilder {
outputParamsURL: outputParamsURL, outputParamsURL: outputParamsURL,
spendingKey: spendingKey, spendingKey: spendingKey,
unifiedViewingKey: uvk, unifiedViewingKey: uvk,
walletBirthday: walletBirthday) walletBirthday: walletBirthday,
network: network)
} }
} }

View File

@ -26,34 +26,12 @@ class TransactionEnhancementTests: XCTestCase {
let mockLatestHeight = BlockHeight(663250) let mockLatestHeight = BlockHeight(663250)
let targetLatestHeight = BlockHeight(663251) let targetLatestHeight = BlockHeight(663251)
let walletBirthday = BlockHeight(663150) let walletBirthday = BlockHeight(663150)
let network = DarksideWalletDNetwork()
let branchID = "2bb40e60"
let chainName = "main"
override func setUpWithError() throws { override func setUpWithError() throws {
logger = SampleLogger(logLevel: .debug) logger = SampleLogger(logLevel: .debug)
var config = CompactBlockProcessor.Configuration.standard
let rustBackend = ZcashRustBackend.self
let birthday = WalletBirthday.birthday(with: walletBirthday)
config.walletBirthday = birthday.height
processorConfig = config
try? FileManager.default.removeItem(at: processorConfig.cacheDb)
try? FileManager.default.removeItem(at: processorConfig.dataDb)
_ = rustBackend.initAccountsTable(dbData: processorConfig.dataDb, seed: TestSeed().seed(), accounts: 1)
let service = DarksideWalletService()
darksideWalletService = service
let storage = CompactBlockStorage.init(connectionProvider: SimpleConnectionProvider(path: processorConfig.cacheDb.absoluteString))
try! storage.createTable()
downloader = CompactBlockDownloader(service: service, storage: storage)
processor = CompactBlockProcessor(service: service,
storage: storage,
backend: rustBackend,
config: processorConfig)
downloadStartedExpect = XCTestExpectation(description: self.description + " downloadStartedExpect") downloadStartedExpect = XCTestExpectation(description: self.description + " downloadStartedExpect")
stopNotificationExpectation = XCTestExpectation(description: self.description + " stopNotificationExpectation") stopNotificationExpectation = XCTestExpectation(description: self.description + " stopNotificationExpectation")
updatedNotificationExpectation = XCTestExpectation(description: self.description + " updatedNotificationExpectation") updatedNotificationExpectation = XCTestExpectation(description: self.description + " updatedNotificationExpectation")
@ -66,11 +44,39 @@ class TransactionEnhancementTests: XCTestCase {
waitExpectation = XCTestExpectation(description: self.description + "waitExpectation") waitExpectation = XCTestExpectation(description: self.description + "waitExpectation")
let birthday = WalletBirthday.birthday(with: walletBirthday, network: network)
let config = CompactBlockProcessor.Configuration.standard(for: self.network, walletBirthday: birthday.height)
let rustBackend = ZcashRustBackend.self
processorConfig = config
try? FileManager.default.removeItem(at: processorConfig.cacheDb)
try? FileManager.default.removeItem(at: processorConfig.dataDb)
_ = rustBackend.initAccountsTable(dbData: processorConfig.dataDb, seed: TestSeed().seed(), accounts: 1,networkType: network.networkType)
_ = try rustBackend.initDataDb(dbData: processorConfig.dataDb, networkType: network.networkType)
_ = try rustBackend.initBlocksTable(dbData: processorConfig.dataDb, height: Int32(birthday.height), hash: birthday.hash, time: birthday.time, saplingTree: birthday.tree, networkType: network.networkType)
let service = DarksideWalletService()
darksideWalletService = service
let storage = CompactBlockStorage.init(connectionProvider: SimpleConnectionProvider(path: processorConfig.cacheDb.absoluteString))
try! storage.createTable()
downloader = CompactBlockDownloader(service: service, storage: storage)
processor = CompactBlockProcessor(service: service,
storage: storage,
backend: rustBackend,
config: processorConfig)
NotificationCenter.default.addObserver(self, selector: #selector(processorFailed(_:)), name: Notification.Name.blockProcessorFailed, object: processor) NotificationCenter.default.addObserver(self, selector: #selector(processorFailed(_:)), name: Notification.Name.blockProcessorFailed, object: processor)
} }
override func tearDownWithError() throws { override func tearDownWithError() throws {
try! FileManager.default.removeItem(at: processorConfig.cacheDb) try? FileManager.default.removeItem(at: processorConfig.cacheDb)
try? FileManager.default.removeItem(at: processorConfig.dataDb) try? FileManager.default.removeItem(at: processorConfig.dataDb)
downloadStartedExpect.unsubscribeFromNotifications() downloadStartedExpect.unsubscribeFromNotifications()
stopNotificationExpectation.unsubscribeFromNotifications() stopNotificationExpectation.unsubscribeFromNotifications()
@ -100,7 +106,7 @@ class TransactionEnhancementTests: XCTestCase {
func testBasicEnhacement() throws { func testBasicEnhacement() throws {
let targetLatestHeight = BlockHeight(663250) let targetLatestHeight = BlockHeight(663250)
let walletBirthday = WalletBirthday.birthday(with: 663151).height let walletBirthday = WalletBirthday.birthday(with: 663151, network: network).height
try basicEnhancementTest(latestHeight: targetLatestHeight, walletBirthday: walletBirthday) try basicEnhancementTest(latestHeight: targetLatestHeight, walletBirthday: walletBirthday)
} }
@ -108,12 +114,15 @@ class TransactionEnhancementTests: XCTestCase {
func basicEnhancementTest(latestHeight: BlockHeight, walletBirthday: BlockHeight) throws { func basicEnhancementTest(latestHeight: BlockHeight, walletBirthday: BlockHeight) throws {
do { do {
try darksideWalletService.reset(saplingActivation: 663150, branchID: branchID, chainName: chainName)
try darksideWalletService.useDataset(DarksideDataset.beforeReOrg.rawValue) try darksideWalletService.useDataset(DarksideDataset.beforeReOrg.rawValue)
try darksideWalletService.applyStaged(nextLatestHeight: 663200)
} catch { } catch {
XCTFail("Error: \(error)") XCTFail("Error: \(error)")
return return
} }
sleep(3)
/** /**
connect to dLWD connect to dLWD
request latest height -> receive firstLatestHeight request latest height -> receive firstLatestHeight
@ -124,12 +133,13 @@ class TransactionEnhancementTests: XCTestCase {
XCTFail("Error: \(error)") XCTFail("Error: \(error)")
return return
} }
/** /**
download and sync blocks from walletBirthday to firstLatestHeight download and sync blocks from walletBirthday to firstLatestHeight
*/ */
do { do {
try startProcessing() try startProcessing()
} catch { } catch {
@ -155,3 +165,4 @@ class TransactionEnhancementTests: XCTestCase {
} }
} }

View File

@ -15,7 +15,8 @@ class WalletTests: XCTestCase {
var dbData: URL! = nil var dbData: URL! = nil
var paramDestination: URL! = nil var paramDestination: URL! = nil
var cacheData: URL! = nil var cacheData: URL! = nil
var network = ZcashNetworkBuilder.network(for: .testnet)
var seedData: Data = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")!
override func setUp() { override func setUp() {
dbData = try! __dataDbURL() dbData = try! __dataDbURL()
@ -29,23 +30,30 @@ class WalletTests: XCTestCase {
} }
} }
// func testWalletInitialization() { func testWalletInitialization() throws {
//
// let wallet = Initializer(cacheDbURL: cacheData, let derivationTool = DerivationTool(networkType: network.networkType)
// dataDbURL: dbData, let uvk = try derivationTool.deriveUnifiedViewingKeysFromSeed(seedData.bytes, numberOfAccounts: 1)
// pendingDbURL: try! TestDbBuilder.pendingTransactionsDbURL(), let wallet = Initializer(cacheDbURL: try __cacheDbURL(),
// endpoint: LightWalletEndpointBuilder.default, dataDbURL: try __dataDbURL(),
// spendParamsURL: try! __spendParamsURL(), pendingDbURL: try TestDbBuilder.pendingTransactionsDbURL(),
// outputParamsURL: try! __outputParamsURL() endpoint: LightWalletEndpointBuilder.default,
// ) network: network,
// spendParamsURL: try __spendParamsURL(),
// XCTAssertNoThrow(try wallet.initialize(viewingKeys: ["zxviewtestsapling1qwxyzvdmqqqqpqy3knx32fpja779wzg76kmglgguvr74g773f3aw3gy37rar6y9d37knvskz6thnea55s05cz3a7q38835hq4w58yevn763cn2wf7k2mpj247ynxpt9qm0nn39slkz5dk572hxr43pxqtg5kz3pqcj8z8uhz0l2vx8gxe90uf4pgw7ks23f0hz2hm47k9ym42cmns3tenhxzlyur2nvx68h4fmk9nrs44ymcqz434zsuxpvhklrjzn00gc43fdghn5szc5x2w"], walletBirthday: 663194)) outputParamsURL: try __outputParamsURL(),
// viewingKeys: uvk,
// // fileExists actually sucks, so attempting to delete the file and checking what happens is far better :) walletBirthday: 663194)
// XCTAssertNoThrow( try FileManager.default.removeItem(at: dbData!) )
// // TODO: Initialize cacheDB on start, will be done when Synchronizer is ready and integrated
//// XCTAssertNoThrow( try FileManager.default.removeItem(at: cacheData!) )
// } let synchronizer = try SDKSynchronizer(initializer: wallet)
XCTAssertNoThrow(try synchronizer.prepare())
// fileExists actually sucks, so attempting to delete the file and checking what happens is far better :)
XCTAssertNoThrow( try FileManager.default.removeItem(at: dbData!) )
// TODO: Initialize cacheDB on start, will be done when Synchronizer is ready and integrated
// XCTAssertNoThrow( try FileManager.default.removeItem(at: cacheData!) )
}
} }
struct WalletBirthdayProvider { struct WalletBirthdayProvider {

View File

@ -18,7 +18,7 @@ class ZcashLightClientKitTests: XCTestCase {
var service: LightWalletGRPCService! var service: LightWalletGRPCService!
override func setUp() { override func setUp() {
super.setUp() super.setUp()
service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default) service = LightWalletGRPCService(endpoint: LightWalletEndpoint(address: Constants.address, port: 9067))
latestBlockHeight = try! service.latestBlock().compactBlockHeight()! latestBlockHeight = try! service.latestBlock().compactBlockHeight()!
} }

View File

@ -16,6 +16,9 @@ class ZcashRustBackendTests: XCTestCase {
let spendingKey = "secret-extended-key-test1qvpevftsqqqqpqy52ut2vv24a2qh7nsukew7qg9pq6djfwyc3xt5vaxuenshp2hhspp9qmqvdh0gs2ljpwxders5jkwgyhgln0drjqaguaenfhehz4esdl4kwlm5t9q0l6wmzcrvcf5ed6dqzvct3e2ge7f6qdvzhp02m7sp5a0qjssrwpdh7u6tq89hl3wchuq8ljq8r8rwd6xdwh3nry9at80z7amnj3s6ah4jevnvfr08gxpws523z95g6dmn4wm6l3658kd4xcq9rc0qn" let spendingKey = "secret-extended-key-test1qvpevftsqqqqpqy52ut2vv24a2qh7nsukew7qg9pq6djfwyc3xt5vaxuenshp2hhspp9qmqvdh0gs2ljpwxders5jkwgyhgln0drjqaguaenfhehz4esdl4kwlm5t9q0l6wmzcrvcf5ed6dqzvct3e2ge7f6qdvzhp02m7sp5a0qjssrwpdh7u6tq89hl3wchuq8ljq8r8rwd6xdwh3nry9at80z7amnj3s6ah4jevnvfr08gxpws523z95g6dmn4wm6l3658kd4xcq9rc0qn"
let recipientAddress = "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6" let recipientAddress = "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6"
let zpend: Int = 500_000 let zpend: Int = 500_000
let networkType = NetworkType.testnet
override func setUp() { override func setUp() {
dbData = try! __dataDbURL() dbData = try! __dataDbURL()
try? dataDbHandle.setUp() try? dataDbHandle.setUp()
@ -30,9 +33,9 @@ class ZcashRustBackendTests: XCTestCase {
func testInitWithShortSeedAndFail() { func testInitWithShortSeedAndFail() {
let seed = "testreferencealice" let seed = "testreferencealice"
XCTAssertNoThrow(try ZcashRustBackend.initDataDb(dbData: dbData!)) XCTAssertNoThrow(try ZcashRustBackend.initDataDb(dbData: dbData!, networkType: networkType))
let _ = ZcashRustBackend.initAccountsTable(dbData: dbData!, seed: Array(seed.utf8), accounts: 1) let _ = ZcashRustBackend.initAccountsTable(dbData: dbData!, seed: Array(seed.utf8), accounts: 1, networkType: networkType)
XCTAssertNotNil(ZcashRustBackend.getLastError()) XCTAssertNotNil(ZcashRustBackend.getLastError())
} }
@ -41,7 +44,7 @@ class ZcashRustBackendTests: XCTestCase {
let seed = Array("testreferencealicetestreferencealice".utf8) let seed = Array("testreferencealicetestreferencealice".utf8)
var spendingKeys: [String]? = nil var spendingKeys: [String]? = nil
XCTAssertNoThrow(try { spendingKeys = try ZcashRustBackend.deriveExtendedSpendingKeys(seed: seed, accounts: 1) }()) XCTAssertNoThrow(try { spendingKeys = try ZcashRustBackend.deriveExtendedSpendingKeys(seed: seed, accounts: 1, networkType: networkType) }())
XCTAssertNotNil(spendingKeys) XCTAssertNotNil(spendingKeys)
XCTAssertFalse(spendingKeys?.first?.isEmpty ?? true) XCTAssertFalse(spendingKeys?.first?.isEmpty ?? true)
@ -52,7 +55,7 @@ class ZcashRustBackendTests: XCTestCase {
let seed = Array("testreferencealicetestreferencealice".utf8) let seed = Array("testreferencealicetestreferencealice".utf8)
var fullViewingKeys: [String]? = nil var fullViewingKeys: [String]? = nil
XCTAssertNoThrow(try { fullViewingKeys = try ZcashRustBackend.deriveExtendedFullViewingKeys(seed: seed, accounts: 1) }()) XCTAssertNoThrow(try { fullViewingKeys = try ZcashRustBackend.deriveExtendedFullViewingKeys(seed: seed, accounts: 1, networkType: networkType) }())
XCTAssertNotNil(fullViewingKeys) XCTAssertNotNil(fullViewingKeys)
XCTAssertFalse(fullViewingKeys?.first?.isEmpty ?? true) XCTAssertFalse(fullViewingKeys?.first?.isEmpty ?? true)
@ -64,7 +67,7 @@ class ZcashRustBackendTests: XCTestCase {
var spendingKeys: [String]? = nil var spendingKeys: [String]? = nil
XCTAssertNoThrow(try { spendingKeys = try ZcashRustBackend.deriveExtendedSpendingKeys(seed: seed, accounts: 1) }()) XCTAssertNoThrow(try { spendingKeys = try ZcashRustBackend.deriveExtendedSpendingKeys(seed: seed, accounts: 1, networkType: networkType) }())
XCTAssertNotNil(spendingKeys) XCTAssertNotNil(spendingKeys)
XCTAssertFalse(spendingKeys?.first?.isEmpty ?? true) XCTAssertFalse(spendingKeys?.first?.isEmpty ?? true)
@ -74,7 +77,7 @@ class ZcashRustBackendTests: XCTestCase {
return return
} }
XCTAssertNoThrow(try { fullViewingKey = try ZcashRustBackend.deriveExtendedFullViewingKey(spendingKey) }()) XCTAssertNoThrow(try { fullViewingKey = try ZcashRustBackend.deriveExtendedFullViewingKey(spendingKey, networkType: networkType) }())
XCTAssertNotNil(fullViewingKey) XCTAssertNotNil(fullViewingKey)
XCTAssertFalse(fullViewingKey?.isEmpty ?? true) XCTAssertFalse(fullViewingKey?.isEmpty ?? true)
@ -86,24 +89,24 @@ class ZcashRustBackendTests: XCTestCase {
return return
} }
let seed = "testreferencealicetestreferencealice" let seed = "testreferencealicetestreferencealice"
XCTAssertNoThrow(try ZcashRustBackend.initDataDb(dbData: dbData!)) XCTAssertNoThrow(try ZcashRustBackend.initDataDb(dbData: dbData!, networkType: networkType))
XCTAssertEqual(ZcashRustBackend.getLastError(), nil) XCTAssertEqual(ZcashRustBackend.getLastError(), nil)
XCTAssertNotNil(ZcashRustBackend.initAccountsTable(dbData: dbData!, seed: Array(seed.utf8), accounts: 1)) XCTAssertNotNil(ZcashRustBackend.initAccountsTable(dbData: dbData!, seed: Array(seed.utf8), accounts: 1, networkType: networkType))
XCTAssertEqual(ZcashRustBackend.getLastError(), nil) XCTAssertEqual(ZcashRustBackend.getLastError(), nil)
let addr = ZcashRustBackend.getAddress(dbData: dbData!, account: 0) let addr = ZcashRustBackend.getAddress(dbData: dbData!, account: 0, networkType: networkType)
XCTAssertEqual(ZcashRustBackend.getLastError(), nil) XCTAssertEqual(ZcashRustBackend.getLastError(), nil)
XCTAssertEqual(addr, Optional("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc")) XCTAssertEqual(addr, Optional("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc"))
XCTAssertTrue(ZcashRustBackend.scanBlocks(dbCache: cacheDb, dbData: dbData)) XCTAssertTrue(ZcashRustBackend.scanBlocks(dbCache: cacheDb, dbData: dbData, networkType: networkType))
} }
func testIsValidTransparentAddressFalse() { func testIsValidTransparentAddressFalse() {
var isValid: Bool? = nil var isValid: Bool? = nil
XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidTransparentAddress("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc") }()) XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidTransparentAddress("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc", networkType: networkType) }())
if let valid = isValid { if let valid = isValid {
XCTAssertFalse(valid) XCTAssertFalse(valid)
@ -117,7 +120,7 @@ class ZcashRustBackendTests: XCTestCase {
func testIsValidTransparentAddressTrue() { func testIsValidTransparentAddressTrue() {
var isValid: Bool? = nil var isValid: Bool? = nil
XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidTransparentAddress("tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7") }()) XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidTransparentAddress("tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7", networkType: networkType) }())
if let valid = isValid { if let valid = isValid {
XCTAssertTrue(valid) XCTAssertTrue(valid)
@ -129,7 +132,7 @@ class ZcashRustBackendTests: XCTestCase {
func testIsValidShieldedAddressTrue() { func testIsValidShieldedAddressTrue() {
var isValid: Bool? = nil var isValid: Bool? = nil
XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidShieldedAddress("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc") }()) XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidShieldedAddress("ztestsapling12k9m98wmpjts2m56wc60qzhgsfvlpxcwah268xk5yz4h942sd58jy3jamqyxjwums6hw7kfa4cc", networkType: networkType) }())
if let valid = isValid { if let valid = isValid {
XCTAssertTrue(valid) XCTAssertTrue(valid)
@ -141,7 +144,7 @@ class ZcashRustBackendTests: XCTestCase {
func testIsValidShieldedAddressFalse() { func testIsValidShieldedAddressFalse() {
var isValid: Bool? = nil var isValid: Bool? = nil
XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidShieldedAddress("tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7") }()) XCTAssertNoThrow(try { isValid = try ZcashRustBackend.isValidShieldedAddress("tmSwpioc7reeoNrYB9SKpWkurJz3yEj3ee7", networkType: networkType) }())
if let valid = isValid { if let valid = isValid {
XCTAssertFalse(valid) XCTAssertFalse(valid)

View File

@ -199,3 +199,38 @@ class DarksideWalletService: LightWalletService {
} }
} }
class DarksideWalletDConstants: NetworkConstants {
static var SAPLING_ACTIVATION_HEIGHT: BlockHeight {
663150
}
static var DEFAULT_DATA_DB_NAME: String {
ZcashSDKMainnetConstants.DEFAULT_DATA_DB_NAME
}
static var DEFAULT_CACHES_DB_NAME: String {
ZcashSDKMainnetConstants.DEFAULT_CACHES_DB_NAME
}
static var DEFAULT_PENDING_DB_NAME: String {
ZcashSDKMainnetConstants.DEFAULT_PENDING_DB_NAME
}
static var DEFAULT_DB_NAME_PREFIX: String {
ZcashSDKMainnetConstants.DEFAULT_DB_NAME_PREFIX
}
static var FEE_CHANGE_HEIGHT: BlockHeight {
ZcashSDKMainnetConstants.FEE_CHANGE_HEIGHT
}
}
class DarksideWalletDNetwork: ZcashNetwork {
var constants: NetworkConstants.Type = DarksideWalletDConstants.self
var networkType = NetworkType.mainnet
}

View File

@ -68,13 +68,15 @@ class MockLightWalletService: LightWalletService {
} }
private var service = LightWalletGRPCService(endpoint: LightWalletEndpointBuilder.default) private var service: LightWalletService
var latestHeight: BlockHeight var latestHeight: BlockHeight
init(latestBlockHeight: BlockHeight) { init(latestBlockHeight: BlockHeight, service: LightWalletService) {
self.latestHeight = latestBlockHeight self.latestHeight = latestBlockHeight
self.service = service
} }
func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void) { func latestBlockHeight(result: @escaping (Result<BlockHeight, LightWalletServiceError>) -> Void) {
DispatchQueue.global().asyncAfter(deadline: .now() + 1) { DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
result(.success(self.latestHeight)) result(.success(self.latestHeight))

View File

@ -44,10 +44,15 @@ class MockTransactionRepository: TransactionRepository {
receivedCount + sentCount receivedCount + sentCount
} }
init(unminedCount: Int, receivedCount: Int, sentCount: Int) { var network: ZcashNetwork
init(unminedCount: Int,
receivedCount: Int,
sentCount: Int,
network: ZcashNetwork) {
self.unminedCount = unminedCount self.unminedCount = unminedCount
self.receivedCount = receivedCount self.receivedCount = receivedCount
self.sentCount = sentCount self.sentCount = sentCount
self.network = network
} }
func generate() { func generate() {
@ -148,7 +153,7 @@ class MockTransactionRepository: TransactionRepository {
} }
func randomBlockHeight() -> BlockHeight { func randomBlockHeight() -> BlockHeight {
BlockHeight.random(in: ZcashSDK.SAPLING_ACTIVATION_HEIGHT ... 1_000_000) BlockHeight.random(in: network.constants.SAPLING_ACTIVATION_HEIGHT ... 1_000_000)
} }
func randomTimeInterval() -> TimeInterval { func randomTimeInterval() -> TimeInterval {
Double.random(in: Date().timeIntervalSince1970 - 1000000.0 ... Date().timeIntervalSince1970) Double.random(in: Date().timeIntervalSince1970 - 1000000.0 ... Date().timeIntervalSince1970)

View File

@ -77,104 +77,108 @@ extension LightWalletServiceMockResponse {
} }
class MockRustBackend: ZcashRustBackendWelding { class MockRustBackend: ZcashRustBackendWelding {
static func clearUtxos(dbData: URL, address: String, sinceHeight: BlockHeight, networkType: NetworkType) throws -> Int32 {
static func getNearestRewindHeight(dbData: URL, height: Int32) -> Int32 {
-1 -1
} }
static func clearUtxos(dbData: URL, address: String, sinceHeight: BlockHeight) throws -> Int32 {
static func getNearestRewindHeight(dbData: URL, height: Int32, networkType: NetworkType) -> Int32 {
-1 -1
} }
static func initAccountsTable(dbData: URL, uvks: [UnifiedViewingKey]) throws -> Bool { static func network(dbData: URL, address: String, sinceHeight: BlockHeight, networkType: NetworkType) throws -> Int32 {
-1
}
static func initAccountsTable(dbData: URL, uvks: [UnifiedViewingKey], networkType: NetworkType) throws -> Bool {
false false
} }
static func getVerifiedTransparentBalance(dbData: URL, address: String) throws -> Int64 { static func getVerifiedTransparentBalance(dbData: URL, address: String, networkType: NetworkType) throws -> Int64 {
-1 -1
} }
static func getTransparentBalance(dbData: URL, address: String) throws -> Int64 { static func getTransparentBalance(dbData: URL, address: String, networkType: NetworkType) throws -> Int64 {
-1 -1
} }
static func putUnspentTransparentOutput(dbData: URL, address: String, txid: [UInt8], index: Int, script: [UInt8], value: Int64, height: BlockHeight) throws -> Bool { static func putUnspentTransparentOutput(dbData: URL, address: String, txid: [UInt8], index: Int, script: [UInt8], value: Int64, height: BlockHeight, networkType: NetworkType) throws -> Bool {
false false
} }
static func downloadedUtxoBalance(dbData: URL, address: String) throws -> WalletBalance { static func downloadedUtxoBalance(dbData: URL, address: String, networkType: NetworkType) throws -> WalletBalance {
throw RustWeldingError.genericError(message: "unimplemented") throw RustWeldingError.genericError(message: "unimplemented")
} }
static func createToAddress(dbData: URL, account: Int32, extsk: String, to: String, value: Int64, memo: String?, spendParamsPath: String, outputParamsPath: String) -> Int64 { static func createToAddress(dbData: URL, account: Int32, extsk: String, to: String, value: Int64, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64 {
-1 -1
} }
static func shieldFunds(dbCache: URL, dbData: URL, account: Int32, tsk: String, extsk: String, memo: String?, spendParamsPath: String, outputParamsPath: String) -> Int64 { static func shieldFunds(dbCache: URL, dbData: URL, account: Int32, tsk: String, extsk: String, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64 {
-1 -1
} }
static func deriveTransparentAddressFromSeed(seed: [UInt8], account: Int, index: Int) throws -> String? { static func deriveTransparentAddressFromSeed(seed: [UInt8], account: Int, index: Int, networkType: NetworkType) throws -> String? {
throw KeyDerivationErrors.unableToDerive throw KeyDerivationErrors.unableToDerive
} }
static func deriveTransparentPrivateKeyFromSeed(seed: [UInt8], account: Int, index: Int) throws -> String? { static func deriveTransparentPrivateKeyFromSeed(seed: [UInt8], account: Int, index: Int, networkType: NetworkType) throws -> String? {
throw KeyDerivationErrors.unableToDerive throw KeyDerivationErrors.unableToDerive
} }
static func deriveTransparentAddressFromSecretKey(_ tsk: String) throws -> String? { static func deriveTransparentAddressFromSecretKey(_ tsk: String, networkType: NetworkType) throws -> String? {
throw KeyDerivationErrors.unableToDerive throw KeyDerivationErrors.unableToDerive
} }
static func derivedTransparentAddressFromPublicKey(_ pubkey: String) throws -> String { static func derivedTransparentAddressFromPublicKey(_ pubkey: String, networkType: NetworkType) throws -> String {
throw KeyDerivationErrors.unableToDerive throw KeyDerivationErrors.unableToDerive
} }
static func deriveUnifiedViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int) throws -> [UnifiedViewingKey] { static func deriveUnifiedViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int, networkType: NetworkType) throws -> [UnifiedViewingKey] {
throw KeyDerivationErrors.unableToDerive throw KeyDerivationErrors.unableToDerive
} }
static func isValidExtendedFullViewingKey(_ key: String) throws -> Bool { static func isValidExtendedFullViewingKey(_ key: String, networkType: NetworkType) throws -> Bool {
false false
} }
static func deriveTransparentPrivateKeyFromSeed(seed: [UInt8]) throws -> String? { static func deriveTransparentPrivateKeyFromSeed(seed: [UInt8], networkType: NetworkType) throws -> String? {
nil nil
} }
static func initAccountsTable(dbData: URL, exfvks: [String]) throws -> Bool { static func initAccountsTable(dbData: URL, exfvks: [String], networkType: NetworkType) throws -> Bool {
false false
} }
static func deriveTransparentAddressFromSeed(seed: [UInt8]) throws -> String? { static func deriveTransparentAddressFromSeed(seed: [UInt8], networkType: NetworkType) throws -> String? {
nil nil
} }
static func deriveExtendedFullViewingKeys(seed: [UInt8], accounts: Int32) throws -> [String]? { static func deriveExtendedFullViewingKeys(seed: [UInt8], accounts: Int32, networkType: NetworkType) throws -> [String]? {
nil nil
} }
static func deriveExtendedSpendingKeys(seed: [UInt8], accounts: Int32) throws -> [String]? { static func deriveExtendedSpendingKeys(seed: [UInt8], accounts: Int32, networkType: NetworkType) throws -> [String]? {
nil nil
} }
static func deriveShieldedAddressFromSeed(seed: [UInt8], accountIndex: Int32) throws -> String? { static func deriveShieldedAddressFromSeed(seed: [UInt8], accountIndex: Int32, networkType: NetworkType) throws -> String? {
nil nil
} }
static func deriveShieldedAddressFromViewingKey(_ extfvk: String) throws -> String? { static func deriveShieldedAddressFromViewingKey(_ extfvk: String, networkType: NetworkType) throws -> String? {
nil nil
} }
static func consensusBranchIdFor(height: Int32) throws -> Int32 { static func consensusBranchIdFor(height: Int32, networkType: NetworkType) throws -> Int32 {
guard let c = consensusBranchID else { guard let c = consensusBranchID else {
return try rustBackend.consensusBranchIdFor(height: height) return try rustBackend.consensusBranchIdFor(height: height, networkType: networkType)
} }
return c return c
} }
static var networkType = NetworkType.testnet
static var mockDataDb = false static var mockDataDb = false
static var mockAcounts = false static var mockAcounts = false
static var mockError: RustWeldingError? static var mockError: RustWeldingError?
@ -202,61 +206,61 @@ class MockRustBackend: ZcashRustBackendWelding {
mockLastError ?? rustBackend.getLastError() mockLastError ?? rustBackend.getLastError()
} }
static func isValidShieldedAddress(_ address: String) throws -> Bool { static func isValidShieldedAddress(_ address: String, networkType: NetworkType) throws -> Bool {
true true
} }
static func isValidTransparentAddress(_ address: String) throws -> Bool { static func isValidTransparentAddress(_ address: String, networkType: NetworkType) throws -> Bool {
true true
} }
static func initDataDb(dbData: URL) throws { static func initDataDb(dbData: URL, networkType: NetworkType) throws {
if !mockDataDb { if !mockDataDb {
try rustBackend.initDataDb(dbData: dbData) try rustBackend.initDataDb(dbData: dbData, networkType: networkType)
} }
} }
static func initAccountsTable(dbData: URL, seed: [UInt8], accounts: Int32) -> [String]? { static func initAccountsTable(dbData: URL, seed: [UInt8], accounts: Int32, networkType: NetworkType) -> [String]? {
mockAccounts ?? rustBackend.initAccountsTable(dbData: dbData, seed: seed, accounts: accounts) mockAccounts ?? rustBackend.initAccountsTable(dbData: dbData, seed: seed, accounts: accounts, networkType: networkType)
} }
static func initBlocksTable(dbData: URL, height: Int32, hash: String, time: UInt32, saplingTree: String) throws { static func initBlocksTable(dbData: URL, height: Int32, hash: String, time: UInt32, saplingTree: String, networkType: NetworkType) throws {
if !mockDataDb { if !mockDataDb {
try rustBackend.initBlocksTable(dbData: dbData, height: height, hash: hash, time: time, saplingTree: saplingTree) try rustBackend.initBlocksTable(dbData: dbData, height: height, hash: hash, time: time, saplingTree: saplingTree, networkType: networkType)
} }
} }
static func getAddress(dbData: URL, account: Int32) -> String? { static func getAddress(dbData: URL, account: Int32, networkType: NetworkType) -> String? {
mockAddresses?[Int(account)] ?? rustBackend.getAddress(dbData: dbData, account: account) mockAddresses?[Int(account)] ?? rustBackend.getAddress(dbData: dbData, account: account, networkType: networkType)
} }
static func getBalance(dbData: URL, account: Int32) -> Int64 { static func getBalance(dbData: URL, account: Int32, networkType: NetworkType) -> Int64 {
mockBalance ?? rustBackend.getBalance(dbData: dbData, account: account) mockBalance ?? rustBackend.getBalance(dbData: dbData, account: account, networkType: networkType)
} }
static func getVerifiedBalance(dbData: URL, account: Int32) -> Int64 { static func getVerifiedBalance(dbData: URL, account: Int32, networkType: NetworkType) -> Int64 {
mockVerifiedBalance ?? rustBackend.getVerifiedBalance(dbData: dbData, account: account) mockVerifiedBalance ?? rustBackend.getVerifiedBalance(dbData: dbData, account: account, networkType: networkType)
} }
static func getReceivedMemoAsUTF8(dbData: URL, idNote: Int64) -> String? { static func getReceivedMemoAsUTF8(dbData: URL, idNote: Int64, networkType: NetworkType) -> String? {
mockMemo ?? rustBackend.getReceivedMemoAsUTF8(dbData: dbData, idNote: idNote) mockMemo ?? rustBackend.getReceivedMemoAsUTF8(dbData: dbData, idNote: idNote, networkType: networkType)
} }
static func getSentMemoAsUTF8(dbData: URL, idNote: Int64) -> String? { static func getSentMemoAsUTF8(dbData: URL, idNote: Int64, networkType: NetworkType) -> String? {
mockSentMemo ?? getSentMemoAsUTF8(dbData: dbData, idNote: idNote) mockSentMemo ?? getSentMemoAsUTF8(dbData: dbData, idNote: idNote, networkType: networkType)
} }
static func validateCombinedChain(dbCache: URL, dbData: URL) -> Int32 { static func validateCombinedChain(dbCache: URL, dbData: URL, networkType: NetworkType) -> Int32 {
if let rate = self.mockValidateCombinedChainSuccessRate { if let rate = self.mockValidateCombinedChainSuccessRate {
if shouldSucceed(successRate: rate) { if shouldSucceed(successRate: rate) {
return validationResult(dbCache: dbCache, dbData: dbData) return validationResult(dbCache: dbCache, dbData: dbData, networkType: networkType)
} else { } else {
return Int32(mockValidateCombinedChainFailureHeight) return Int32(mockValidateCombinedChainFailureHeight)
} }
} else if let attempts = self.mockValidateCombinedChainFailAfterAttempts { } else if let attempts = self.mockValidateCombinedChainFailAfterAttempts {
self.mockValidateCombinedChainFailAfterAttempts = attempts - 1 self.mockValidateCombinedChainFailAfterAttempts = attempts - 1
if attempts > 0 { if attempts > 0 {
return validationResult(dbCache: dbCache, dbData: dbData) return validationResult(dbCache: dbCache, dbData: dbData, networkType: networkType)
} else { } else {
if attempts == 0 { if attempts == 0 {
@ -264,38 +268,38 @@ class MockRustBackend: ZcashRustBackendWelding {
} else if attempts < 0 && mockValidateCombinedChainKeepFailing { } else if attempts < 0 && mockValidateCombinedChainKeepFailing {
return Int32(mockValidateCombinedChainFailureHeight) return Int32(mockValidateCombinedChainFailureHeight)
} else { } else {
return validationResult(dbCache: dbCache, dbData: dbData) return validationResult(dbCache: dbCache, dbData: dbData, networkType: networkType)
} }
} }
} }
return rustBackend.validateCombinedChain(dbCache: dbCache, dbData: dbData) return rustBackend.validateCombinedChain(dbCache: dbCache, dbData: dbData, networkType: networkType)
} }
private static func validationResult(dbCache: URL, dbData: URL) -> Int32{ private static func validationResult(dbCache: URL, dbData: URL, networkType: NetworkType) -> Int32{
if mockDataDb { if mockDataDb {
return -1 return -1
} else { } else {
return rustBackend.validateCombinedChain(dbCache: dbCache, dbData: dbData) return rustBackend.validateCombinedChain(dbCache: dbCache, dbData: dbData, networkType: networkType)
} }
} }
static func rewindToHeight(dbData: URL, height: Int32) -> Bool { static func rewindToHeight(dbData: URL, height: Int32, networkType: NetworkType) -> Bool {
mockDataDb ? true : rustBackend.rewindToHeight(dbData: dbData, height: height) mockDataDb ? true : rustBackend.rewindToHeight(dbData: dbData, height: height, networkType: networkType)
} }
static func scanBlocks(dbCache: URL, dbData: URL, limit: UInt32) -> Bool { static func scanBlocks(dbCache: URL, dbData: URL, limit: UInt32, networkType: NetworkType) -> Bool {
if let rate = mockScanblocksSuccessRate { if let rate = mockScanblocksSuccessRate {
if shouldSucceed(successRate: rate) { if shouldSucceed(successRate: rate) {
return mockDataDb ? true : rustBackend.scanBlocks(dbCache: dbCache, dbData: dbData) return mockDataDb ? true : rustBackend.scanBlocks(dbCache: dbCache, dbData: dbData, networkType: networkType)
} else { } else {
return false return false
} }
} }
return rustBackend.scanBlocks(dbCache: dbCache, dbData: dbData) return rustBackend.scanBlocks(dbCache: dbCache, dbData: dbData, networkType: Self.networkType)
} }
static func createToAddress(dbData: URL, account: Int32, extsk: String, consensusBranchId: Int32, to: String, value: Int64, memo: String?, spendParamsPath: String, outputParamsPath: String) -> Int64 { static func createToAddress(dbData: URL, account: Int32, extsk: String, consensusBranchId: Int32, to: String, value: Int64, memo: String?, spendParamsPath: String, outputParamsPath: String, networkType: NetworkType) -> Int64 {
// mockCreateToAddress ?? rustBackend.createToAddress(dbData: dbData, account: account, extsk: extsk, consensusBranchId: consensusBranchId, to: to, value: value, memo: memo, spendParamsPath: spendParamsPath, outputParamsPath: outputParamsPath) // mockCreateToAddress ?? rustBackend.createToAddress(dbData: dbData, account: account, extsk: extsk, consensusBranchId: consensusBranchId, to: to, value: value, memo: memo, spendParamsPath: spendParamsPath, outputParamsPath: outputParamsPath)
-1 -1
} }
@ -305,19 +309,19 @@ class MockRustBackend: ZcashRustBackendWelding {
return random <= successRate return random <= successRate
} }
static func deriveExtendedFullViewingKey(_ spendingKey: String) throws -> String? { static func deriveExtendedFullViewingKey(_ spendingKey: String, networkType: NetworkType) throws -> String? {
nil nil
} }
static func deriveExtendedFullViewingKeys(seed: String, accounts: Int32) throws -> [String]? { static func deriveExtendedFullViewingKeys(seed: String, accounts: Int32, networkType: NetworkType) throws -> [String]? {
nil nil
} }
static func deriveExtendedSpendingKeys(seed: String, accounts: Int32) throws -> [String]? { static func deriveExtendedSpendingKeys(seed: String, accounts: Int32, networkType: NetworkType) throws -> [String]? {
nil nil
} }
static func decryptAndStoreTransaction(dbData: URL, tx: [UInt8]) -> Bool { static func decryptAndStoreTransaction(dbData: URL, tx: [UInt8], networkType: NetworkType) -> Bool {
false false
} }

View File

@ -15,6 +15,14 @@ class LightWalletEndpointBuilder {
static var `default`: LightWalletEndpoint { static var `default`: LightWalletEndpoint {
LightWalletEndpoint(address: Constants.address, port: 9067, secure: false) LightWalletEndpoint(address: Constants.address, port: 9067, secure: false)
} }
static var publicTestnet: LightWalletEndpoint {
LightWalletEndpoint(address: "testnet.lightwalletd.com", port: 9067, secure: true)
}
static var eccTestnet: LightWalletEndpoint {
LightWalletEndpoint(address: "lightwalletd.testnet.electriccoin.co", port: 9067, secure: true)
}
} }
class ChannelProvider { class ChannelProvider {

View File

@ -1,3 +1,50 @@
# 0.12.0-alpha.11
* [Enhancement] Network Agnostic build
# 0.12.0-alpha.10
* Fix: UNIQUE Constraint bug when coming from background. fixed and logged warning to keep investigating
* [New] latestScannedHeight added to SDKSynchronizer
# 0.12.0-alpha.9
* CompactBlockProcessor states don't propagate correctly
# 0.12.0-alpha.8
* target height reporting enhancements
# 0.12.0-alpha.7
* improve status publishing for SDKSynchronizer
* [FIX] missingStartHeight error when scanning from sapling activation
# 0.12.0-alpha.6
* Make sapling parameters default url public
# 0.12.0-alpha.5
* add output files to build phase to avoid CI failures
* fix lint warnings
# 0.12.0-alpha.4
* Tests
* [Fix] Issue #289 main thread lock when validating the server
* [Fix] info single call times out all the time
* make sure operations cancel in a timely manner
* FigureNextBatchOperation.swift tests
* make range function static
# tag: 0.12.0-alpha.3
* getInfo service times out too soon
# 0.12.0-alpha.2
* FIX: processor stalls on reconnection
* Fix warnings
# 0.12.0-alpha.1
* Replace Status for SyncStatus
* fix tests
* Fix Demo App
* fetch operation does not cancel when the previous operations do
* Fix: operations start when they have been canceled already
* fix progress being > 1
* Synchronizing by phases, preview
* Add fetch UTXO operation to compact block processor
* CompactBlock batch download and stream download operation tests pass.
# 0.11.1 # 0.11.1
* [Enhancement] Rewind API has a `.quick` option * [Enhancement] Rewind API has a `.quick` option
# 0.11.0 # 0.11.0

View File

@ -11,7 +11,7 @@ use zcash_client_backend::{
data_api::{ data_api::{
chain::{scan_cached_blocks, validate_chain}, chain::{scan_cached_blocks, validate_chain},
error::Error, error::Error,
wallet::{create_spend_to_address, decrypt_and_store_transaction, shield_funds, ANCHOR_OFFSET}, wallet::{create_spend_to_address, decrypt_and_store_transaction, shield_funds},
WalletRead, WalletRead,
}, },
encoding::{ encoding::{
@ -43,17 +43,13 @@ use zcash_client_sqlite::{
}; };
use zcash_primitives::{ use zcash_primitives::{
block::BlockHash, block::BlockHash,
consensus::{BlockHeight, BranchId, Parameters}, consensus::{BlockHeight, BranchId, Network, Parameters},
memo::{Memo, MemoBytes}, memo::{Memo, MemoBytes},
transaction::{components::Amount, components::OutPoint, Transaction}, transaction::{components::Amount, components::OutPoint, Transaction},
zip32::ExtendedFullViewingKey, zip32::ExtendedFullViewingKey,
legacy::TransparentAddress, legacy::TransparentAddress,
}; };
use zcash_primitives::consensus::Network::{MainNetwork, TestNetwork};
#[cfg(feature = "mainnet")]
use zcash_primitives::consensus::{MainNetwork, MAIN_NETWORK};
#[cfg(not(feature = "mainnet"))]
use zcash_primitives::consensus::{TestNetwork, TEST_NETWORK};
use zcash_proofs::prover::LocalTxProver; use zcash_proofs::prover::LocalTxProver;
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
@ -78,37 +74,21 @@ where
} }
} }
#[cfg(feature = "mainnet")]
pub const NETWORK: MainNetwork = MAIN_NETWORK;
#[cfg(not(feature = "mainnet"))]
pub const NETWORK: TestNetwork = TEST_NETWORK;
#[cfg(feature = "mainnet")]
fn wallet_db( fn wallet_db(
db_data: *const u8, db_data: *const u8,
db_data_len: usize, db_data_len: usize,
) -> Result<WalletDb<MainNetwork>, failure::Error> { network: Network,
) -> Result<WalletDb<Network>, failure::Error> {
let db_data = Path::new(OsStr::from_bytes(unsafe { let db_data = Path::new(OsStr::from_bytes(unsafe {
slice::from_raw_parts(db_data, db_data_len) slice::from_raw_parts(db_data, db_data_len)
})); }));
WalletDb::for_path(db_data, NETWORK) WalletDb::for_path(db_data, network)
.map_err(|e| format_err!("Error opening wallet database connection: {}", e)) .map_err(|e| format_err!("Error opening wallet database connection: {}", e))
} }
#[cfg(not(feature = "mainnet"))] fn block_db(cache_db: *const u8,
fn wallet_db( cache_db_len: usize) -> Result<BlockDb, failure::Error> {
db_data: *const u8,
db_data_len: usize,
) -> Result<WalletDb<TestNetwork>, failure::Error> {
let db_data = Path::new(OsStr::from_bytes(unsafe {
slice::from_raw_parts(db_data, db_data_len)
}));
WalletDb::for_path(db_data, NETWORK)
.map_err(|e| format_err!("Error opening wallet database connection: {}", e))
}
fn block_db(cache_db: *const u8, cache_db_len: usize) -> Result<BlockDb, failure::Error> {
let cache_db = Path::new(OsStr::from_bytes(unsafe { let cache_db = Path::new(OsStr::from_bytes(unsafe {
slice::from_raw_parts(cache_db, cache_db_len) slice::from_raw_parts(cache_db, cache_db_len)
})); }));
@ -136,13 +116,18 @@ pub extern "C" fn zcashlc_clear_last_error() {
/// Sets up the internal structure of the data database. /// Sets up the internal structure of the data database.
#[no_mangle] #[no_mangle]
pub extern "C" fn zcashlc_init_data_database(db_data: *const u8, db_data_len: usize) -> i32 { pub extern "C" fn zcashlc_init_data_database(
db_data: *const u8,
db_data_len: usize,
network_id: u32,
) -> i32 {
let res = catch_panic(|| { let res = catch_panic(|| {
let network = parse_network(network_id)?;
let db_data = Path::new(OsStr::from_bytes(unsafe { let db_data = Path::new(OsStr::from_bytes(unsafe {
slice::from_raw_parts(db_data, db_data_len) slice::from_raw_parts(db_data, db_data_len)
})); }));
WalletDb::for_path(db_data, NETWORK) WalletDb::for_path(db_data, network)
.map(|db| init_wallet_db(&db)) .map(|db| init_wallet_db(&db))
.map(|_| 1) .map(|_| 1)
.map_err(|e| format_err!("Error while initializing data DB: {}", e)) .map_err(|e| format_err!("Error while initializing data DB: {}", e))
@ -164,9 +149,11 @@ pub extern "C" fn zcashlc_init_accounts_table(
seed_len: usize, seed_len: usize,
accounts: i32, accounts: i32,
capacity_ret: *mut usize, capacity_ret: *mut usize,
network_id: u32,
) -> *mut *mut c_char { ) -> *mut *mut c_char {
let res = catch_panic(|| { let res = catch_panic(|| {
let db_data = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_data = wallet_db(db_data, db_data_len, network)?;
let seed = unsafe { slice::from_raw_parts(seed, seed_len) }; let seed = unsafe { slice::from_raw_parts(seed, seed_len) };
let accounts = if accounts >= 0 { let accounts = if accounts >= 0 {
accounts as u32 accounts as u32
@ -175,13 +162,13 @@ pub extern "C" fn zcashlc_init_accounts_table(
}; };
let extsks: Vec<_> = (0..accounts) let extsks: Vec<_> = (0..accounts)
.map(|account| spending_key(&seed, NETWORK.coin_type(), AccountId(account))) .map(|account| spending_key(&seed, network.coin_type(), AccountId(account)))
.collect(); .collect();
let extfvks: Vec<_> = extsks.iter().map(ExtendedFullViewingKey::from).collect(); let extfvks: Vec<_> = extsks.iter().map(ExtendedFullViewingKey::from).collect();
let t_addreses: Vec<_> = (0..accounts) let t_addreses: Vec<_> = (0..accounts)
.map(|account| { .map(|account| {
let tsk = derive_secret_key_from_seed(&NETWORK, &seed, AccountId(account), 0).unwrap(); let tsk = derive_secret_key_from_seed(&network, &seed, AccountId(account), 0).unwrap();
derive_transparent_address_from_secret_key(&tsk) derive_transparent_address_from_secret_key(&tsk)
}).collect(); }).collect();
@ -192,7 +179,7 @@ pub extern "C" fn zcashlc_init_accounts_table(
.iter() .iter()
.map(|extsk| { .map(|extsk| {
let encoded = encode_extended_spending_key( let encoded = encode_extended_spending_key(
NETWORK.hrp_sapling_extended_spending_key(), network.hrp_sapling_extended_spending_key(),
extsk, extsk,
); );
CString::new(encoded).unwrap().into_raw() CString::new(encoded).unwrap().into_raw()
@ -216,9 +203,11 @@ pub extern "C" fn zcashlc_init_accounts_table_with_keys(
db_data: *const u8, db_data: *const u8,
db_data_len: usize, db_data_len: usize,
uvks: *mut FFIUVKBoxedSlice, uvks: *mut FFIUVKBoxedSlice,
network_id: u32,
) -> bool { ) -> bool {
let res = catch_panic(|| { let res = catch_panic(|| {
let db_data = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_data = wallet_db(db_data, db_data_len, network)?;
let s: Box<FFIUVKBoxedSlice> = unsafe { Box::from_raw(uvks) }; let s: Box<FFIUVKBoxedSlice> = unsafe { Box::from_raw(uvks) };
@ -230,7 +219,7 @@ pub extern "C" fn zcashlc_init_accounts_table_with_keys(
for u in slice.into_iter() { for u in slice.into_iter() {
let vkstr = unsafe { CStr::from_ptr(u.extfvk).to_str().unwrap() }; let vkstr = unsafe { CStr::from_ptr(u.extfvk).to_str().unwrap() };
let extfvk = decode_extended_full_viewing_key( let extfvk = decode_extended_full_viewing_key(
NETWORK.hrp_sapling_extended_full_viewing_key(), network.hrp_sapling_extended_full_viewing_key(),
&vkstr, &vkstr,
) )
.unwrap() .unwrap()
@ -263,8 +252,10 @@ pub unsafe extern "C" fn zcashlc_derive_extended_spending_keys(
seed_len: usize, seed_len: usize,
accounts: i32, accounts: i32,
capacity_ret: *mut usize, capacity_ret: *mut usize,
network_id: u32,
) -> *mut *mut c_char { ) -> *mut *mut c_char {
let res = catch_panic(|| { let res = catch_panic(|| {
let network = parse_network(network_id)?;
let seed = slice::from_raw_parts(seed, seed_len); let seed = slice::from_raw_parts(seed, seed_len);
let accounts = if accounts > 0 { let accounts = if accounts > 0 {
accounts as u32 accounts as u32
@ -273,7 +264,7 @@ pub unsafe extern "C" fn zcashlc_derive_extended_spending_keys(
}; };
let extsks: Vec<_> = (0..accounts) let extsks: Vec<_> = (0..accounts)
.map(|account| spending_key(&seed, NETWORK.coin_type(), AccountId(account))) .map(|account| spending_key(&seed, network.coin_type(), AccountId(account)))
.collect(); .collect();
// Return the ExtendedSpendingKeys for the created accounts. // Return the ExtendedSpendingKeys for the created accounts.
@ -281,7 +272,7 @@ pub unsafe extern "C" fn zcashlc_derive_extended_spending_keys(
.iter() .iter()
.map(|extsk| { .map(|extsk| {
let encoded = encode_extended_spending_key( let encoded = encode_extended_spending_key(
NETWORK.hrp_sapling_extended_spending_key(), network.hrp_sapling_extended_spending_key(),
extsk, extsk,
); );
CString::new(encoded).unwrap().into_raw() CString::new(encoded).unwrap().into_raw()
@ -311,10 +302,11 @@ pub struct FFIUVKBoxedSlice {
fn unified_viewing_key_new( fn unified_viewing_key_new(
extfvk: &ExtendedFullViewingKey, extfvk: &ExtendedFullViewingKey,
extpub: &PublicKey) -> FFIUnifiedViewingKey { extpub: &PublicKey,
network: Network) -> FFIUnifiedViewingKey {
let encoded_extfvk = encode_extended_full_viewing_key( let encoded_extfvk = encode_extended_full_viewing_key(
NETWORK.hrp_sapling_extended_full_viewing_key(), network.hrp_sapling_extended_full_viewing_key(),
extfvk, extfvk,
); );
let encoded_pubkey = hex::encode(&extpub.serialize()); let encoded_pubkey = hex::encode(&extpub.serialize());
@ -323,7 +315,6 @@ fn unified_viewing_key_new(
extfvk: CString::new(encoded_extfvk).unwrap().into_raw(), extfvk: CString::new(encoded_extfvk).unwrap().into_raw(),
extpub: CString::new(encoded_pubkey).unwrap().into_raw() extpub: CString::new(encoded_pubkey).unwrap().into_raw()
} }
} }
fn uvk_vec_to_ffi (v: Vec<FFIUnifiedViewingKey>) fn uvk_vec_to_ffi (v: Vec<FFIUnifiedViewingKey>)
@ -360,8 +351,10 @@ pub unsafe extern "C" fn zcashlc_derive_unified_viewing_keys_from_seed(
seed: *const u8, seed: *const u8,
seed_len: usize, seed_len: usize,
accounts: i32, accounts: i32,
network_id: u32,
) -> *mut FFIUVKBoxedSlice { ) -> *mut FFIUVKBoxedSlice {
let res = catch_panic(|| { let res = catch_panic(|| {
let network = parse_network(network_id)?;
let seed = slice::from_raw_parts(seed, seed_len); let seed = slice::from_raw_parts(seed, seed_len);
let accounts = if accounts > 0 { let accounts = if accounts > 0 {
accounts as u32 accounts as u32
@ -371,9 +364,9 @@ pub unsafe extern "C" fn zcashlc_derive_unified_viewing_keys_from_seed(
let uvks: Vec<_> = (0..accounts) let uvks: Vec<_> = (0..accounts)
.map(|account| { .map(|account| {
let extfvk = ExtendedFullViewingKey::from(&spending_key(&seed, NETWORK.coin_type(), AccountId(account))); let extfvk = ExtendedFullViewingKey::from(&spending_key(&seed, network.coin_type(), AccountId(account)));
let extpub = derive_public_key_from_seed(&NETWORK, &seed, AccountId(account), 0).unwrap(); let extpub = derive_public_key_from_seed(&network, &seed, AccountId(account), 0).unwrap();
unified_viewing_key_new(&extfvk, &extpub) unified_viewing_key_new(&extfvk, &extpub, network)
}) })
.collect(); .collect();
Ok(uvk_vec_to_ffi(uvks)) Ok(uvk_vec_to_ffi(uvks))
@ -393,8 +386,10 @@ pub unsafe extern "C" fn zcashlc_derive_extended_full_viewing_keys(
seed_len: usize, seed_len: usize,
accounts: i32, accounts: i32,
capacity_ret: *mut usize, capacity_ret: *mut usize,
network_id: u32,
) -> *mut *mut c_char { ) -> *mut *mut c_char {
let res = catch_panic(|| { let res = catch_panic(|| {
let network = parse_network(network_id)?;
let seed = slice::from_raw_parts(seed, seed_len); let seed = slice::from_raw_parts(seed, seed_len);
let accounts = if accounts > 0 { let accounts = if accounts > 0 {
accounts as u32 accounts as u32
@ -404,7 +399,7 @@ pub unsafe extern "C" fn zcashlc_derive_extended_full_viewing_keys(
let extsks: Vec<_> = (0..accounts) let extsks: Vec<_> = (0..accounts)
.map(|account| { .map(|account| {
ExtendedFullViewingKey::from(&spending_key(&seed, NETWORK.coin_type(), AccountId(account))) ExtendedFullViewingKey::from(&spending_key(&seed, network.coin_type(), AccountId(account)))
}) })
.collect(); .collect();
@ -413,7 +408,7 @@ pub unsafe extern "C" fn zcashlc_derive_extended_full_viewing_keys(
.iter() .iter()
.map(|extsk| { .map(|extsk| {
let encoded = encode_extended_full_viewing_key( let encoded = encode_extended_full_viewing_key(
NETWORK.hrp_sapling_extended_full_viewing_key(), network.hrp_sapling_extended_full_viewing_key(),
extsk, extsk,
); );
CString::new(encoded).unwrap().into_raw() CString::new(encoded).unwrap().into_raw()
@ -434,19 +429,21 @@ pub unsafe extern "C" fn zcashlc_derive_shielded_address_from_seed(
seed: *const u8, seed: *const u8,
seed_len: usize, seed_len: usize,
account_index: i32, account_index: i32,
network_id: u32,
) -> *mut c_char { ) -> *mut c_char {
let res = catch_panic(|| { let res = catch_panic(|| {
let network = parse_network(network_id)?;
let seed = slice::from_raw_parts(seed, seed_len); let seed = slice::from_raw_parts(seed, seed_len);
let account_index = if account_index >= 0 { let account_index = if account_index >= 0 {
account_index as u32 account_index as u32
} else { } else {
return Err(format_err!("accounts argument must be greater than zero")); return Err(format_err!("accounts argument must be greater than zero"));
}; };
let address = spending_key(&seed, NETWORK.coin_type(), AccountId(account_index)) let address = spending_key(&seed, network.coin_type(), AccountId(account_index))
.default_address() .default_address()
.unwrap() .unwrap()
.1; .1;
let address_str = encode_payment_address(NETWORK.hrp_sapling_payment_address(), &address); let address_str = encode_payment_address(network.hrp_sapling_payment_address(), &address);
Ok(CString::new(address_str).unwrap().into_raw()) Ok(CString::new(address_str).unwrap().into_raw())
}); });
unwrap_exc_or_null(res) unwrap_exc_or_null(res)
@ -457,13 +454,15 @@ pub unsafe extern "C" fn zcashlc_derive_shielded_address_from_seed(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn zcashlc_derive_transparent_address_from_public_key( pub unsafe extern "C" fn zcashlc_derive_transparent_address_from_public_key(
pubkey: *const c_char, pubkey: *const c_char,
network_id: u32,
) -> *mut c_char { ) -> *mut c_char {
let res = catch_panic(|| { let res = catch_panic(|| {
let network = parse_network(network_id)?;
let public_key_str = CStr::from_ptr(pubkey).to_str()?; let public_key_str = CStr::from_ptr(pubkey).to_str()?;
let pk = PublicKey::from_str(&public_key_str)?; let pk = PublicKey::from_str(&public_key_str)?;
let taddr = let taddr =
derive_transparent_address_from_public_key(&pk) derive_transparent_address_from_public_key(&pk)
.encode(&NETWORK); .encode(&network);
Ok(CString::new(taddr).unwrap().into_raw()) Ok(CString::new(taddr).unwrap().into_raw())
}); });
@ -475,11 +474,13 @@ pub unsafe extern "C" fn zcashlc_derive_transparent_address_from_public_key(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn zcashlc_derive_shielded_address_from_viewing_key( pub unsafe extern "C" fn zcashlc_derive_shielded_address_from_viewing_key(
extfvk: *const c_char, extfvk: *const c_char,
network_id: u32,
) -> *mut c_char { ) -> *mut c_char {
let res = catch_panic(|| { let res = catch_panic(|| {
let network = parse_network(network_id)?;
let extfvk_string = CStr::from_ptr(extfvk).to_str()?; let extfvk_string = CStr::from_ptr(extfvk).to_str()?;
let extfvk = match decode_extended_full_viewing_key( let extfvk = match decode_extended_full_viewing_key(
NETWORK.hrp_sapling_extended_full_viewing_key(), network.hrp_sapling_extended_full_viewing_key(),
&extfvk_string, &extfvk_string,
) { ) {
Ok(Some(extfvk)) => extfvk, Ok(Some(extfvk)) => extfvk,
@ -494,7 +495,7 @@ pub unsafe extern "C" fn zcashlc_derive_shielded_address_from_viewing_key(
} }
}; };
let address = extfvk.default_address().unwrap().1; let address = extfvk.default_address().unwrap().1;
let address_str = encode_payment_address(NETWORK.hrp_sapling_payment_address(), &address); let address_str = encode_payment_address(network.hrp_sapling_payment_address(), &address);
Ok(CString::new(address_str).unwrap().into_raw()) Ok(CString::new(address_str).unwrap().into_raw())
}); });
unwrap_exc_or_null(res) unwrap_exc_or_null(res)
@ -505,11 +506,13 @@ pub unsafe extern "C" fn zcashlc_derive_shielded_address_from_viewing_key(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn zcashlc_derive_extended_full_viewing_key( pub unsafe extern "C" fn zcashlc_derive_extended_full_viewing_key(
extsk: *const c_char, extsk: *const c_char,
network_id: u32,
) -> *mut c_char { ) -> *mut c_char {
let res = catch_panic(|| { let res = catch_panic(|| {
let network = parse_network(network_id)?;
let extsk = CStr::from_ptr(extsk).to_str()?; let extsk = CStr::from_ptr(extsk).to_str()?;
let extfvk = match decode_extended_spending_key( let extfvk = match decode_extended_spending_key(
NETWORK.hrp_sapling_extended_spending_key(), network.hrp_sapling_extended_spending_key(),
&extsk, &extsk,
) { ) {
Ok(Some(extsk)) => ExtendedFullViewingKey::from(&extsk), Ok(Some(extsk)) => ExtendedFullViewingKey::from(&extsk),
@ -525,7 +528,7 @@ pub unsafe extern "C" fn zcashlc_derive_extended_full_viewing_key(
}; };
let encoded = encode_extended_full_viewing_key( let encoded = encode_extended_full_viewing_key(
NETWORK.hrp_sapling_extended_full_viewing_key(), network.hrp_sapling_extended_full_viewing_key(),
&extfvk, &extfvk,
); );
@ -546,9 +549,11 @@ pub extern "C" fn zcashlc_init_blocks_table(
hash_hex: *const c_char, hash_hex: *const c_char,
time: u32, time: u32,
sapling_tree_hex: *const c_char, sapling_tree_hex: *const c_char,
network_id: u32,
) -> i32 { ) -> i32 {
let res = catch_panic(|| { let res = catch_panic(|| {
let db_data = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_data = wallet_db(db_data, db_data_len,network)?;
let hash = { let hash = {
let mut hash = hex::decode(unsafe { CStr::from_ptr(hash_hex) }.to_str()?).unwrap(); let mut hash = hex::decode(unsafe { CStr::from_ptr(hash_hex) }.to_str()?).unwrap();
hash.reverse(); hash.reverse();
@ -579,9 +584,11 @@ pub extern "C" fn zcashlc_get_address(
db_data: *const u8, db_data: *const u8,
db_data_len: usize, db_data_len: usize,
account: i32, account: i32,
network_id: u32,
) -> *mut c_char { ) -> *mut c_char {
let res = catch_panic(|| { let res = catch_panic(|| {
let db_data = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_data = wallet_db(db_data, db_data_len, network)?;
let account = if account >= 0 { let account = if account >= 0 {
account as u32 account as u32
} else { } else {
@ -592,7 +599,7 @@ pub extern "C" fn zcashlc_get_address(
match (&db_data).get_address(account) { match (&db_data).get_address(account) {
Ok(Some(addr)) => { Ok(Some(addr)) => {
let addr_str = encode_payment_address(NETWORK.hrp_sapling_payment_address(), &addr); let addr_str = encode_payment_address(network.hrp_sapling_payment_address(), &addr);
let c_str_addr = CString::new(addr_str).unwrap(); let c_str_addr = CString::new(addr_str).unwrap();
Ok(c_str_addr.into_raw()) Ok(c_str_addr.into_raw())
} }
@ -610,16 +617,19 @@ pub extern "C" fn zcashlc_get_address(
/// Returns false in any other case /// Returns false in any other case
/// Errors when the provided address belongs to another network /// Errors when the provided address belongs to another network
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn zcashlc_is_valid_shielded_address(address: *const c_char) -> bool { pub unsafe extern "C" fn zcashlc_is_valid_shielded_address(address: *const c_char,
network_id: u32) -> bool {
let res = catch_panic(|| { let res = catch_panic(|| {
let network = parse_network(network_id)?;
let addr = CStr::from_ptr(address).to_str()?; let addr = CStr::from_ptr(address).to_str()?;
Ok(is_valid_shielded_address(&addr)) Ok(is_valid_shielded_address(&addr, &network))
}); });
unwrap_exc_or(res, false) unwrap_exc_or(res, false)
} }
fn is_valid_shielded_address(address: &str) -> bool { fn is_valid_shielded_address(address: &str,
match RecipientAddress::decode(&NETWORK, &address) { network: &Network) -> bool {
match RecipientAddress::decode(network, &address) {
Some(addr) => match addr { Some(addr) => match addr {
RecipientAddress::Shielded(_) => true, RecipientAddress::Shielded(_) => true,
RecipientAddress::Transparent(_) => false, RecipientAddress::Transparent(_) => false,
@ -631,20 +641,24 @@ fn is_valid_shielded_address(address: &str) -> bool {
/// Returns true when the address is valid and transparent. /// Returns true when the address is valid and transparent.
/// Returns false in any other case /// Returns false in any other case
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn zcashlc_is_valid_transparent_address(address: *const c_char) -> bool { pub unsafe extern "C" fn zcashlc_is_valid_transparent_address(address: *const c_char,
network_id: u32) -> bool {
let res = catch_panic(|| { let res = catch_panic(|| {
let network = parse_network(network_id)?;
let addr = CStr::from_ptr(address).to_str()?; let addr = CStr::from_ptr(address).to_str()?;
Ok(is_valid_transparent_address(&addr)) Ok(is_valid_transparent_address(&addr, &network))
}); });
unwrap_exc_or(res, false) unwrap_exc_or(res, false)
} }
/// returns whether the given viewing key is valid or not /// returns whether the given viewing key is valid or not
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn zcashlc_is_valid_viewing_key(key: *const c_char) -> bool { pub unsafe extern "C" fn zcashlc_is_valid_viewing_key(key: *const c_char,
network_id: u32) -> bool {
let res = catch_panic(|| { let res = catch_panic(|| {
let network = parse_network(network_id)?;
let vkstr = CStr::from_ptr(key).to_str()?; let vkstr = CStr::from_ptr(key).to_str()?;
match decode_extended_full_viewing_key(&NETWORK.hrp_sapling_extended_full_viewing_key(), &vkstr) { match decode_extended_full_viewing_key(&network.hrp_sapling_extended_full_viewing_key(), &vkstr) {
Ok(s) => match s { Ok(s) => match s {
None => Ok(false), None => Ok(false),
_ => Ok(true), _ => Ok(true),
@ -654,8 +668,10 @@ pub unsafe extern "C" fn zcashlc_is_valid_viewing_key(key: *const c_char) -> boo
}); });
unwrap_exc_or(res, false) unwrap_exc_or(res, false)
} }
fn is_valid_transparent_address(address: &str) -> bool {
match RecipientAddress::decode(&NETWORK, &address) { fn is_valid_transparent_address(address: &str,
network: &Network) -> bool {
match RecipientAddress::decode(network, &address) {
Some(addr) => match addr { Some(addr) => match addr {
RecipientAddress::Shielded(_) => false, RecipientAddress::Shielded(_) => false,
RecipientAddress::Transparent(_) => true, RecipientAddress::Transparent(_) => true,
@ -666,9 +682,15 @@ fn is_valid_transparent_address(address: &str) -> bool {
/// Returns the balance for the account, including all unspent notes that we know about. /// Returns the balance for the account, including all unspent notes that we know about.
#[no_mangle] #[no_mangle]
pub extern "C" fn zcashlc_get_balance(db_data: *const u8, db_data_len: usize, account: i32) -> i64 { pub extern "C" fn zcashlc_get_balance(
db_data: *const u8,
db_data_len: usize,
account: i32,
network_id: u32,
) -> i64 {
let res = catch_panic(|| { let res = catch_panic(|| {
let db_data = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_data = wallet_db(db_data, db_data_len, network)?;
if account >= 0 { if account >= 0 {
let (_, max_height) = (&db_data) let (_, max_height) = (&db_data)
@ -698,9 +720,11 @@ pub extern "C" fn zcashlc_get_verified_balance(
db_data: *const u8, db_data: *const u8,
db_data_len: usize, db_data_len: usize,
account: i32, account: i32,
network_id: u32,
) -> i64 { ) -> i64 {
let res = catch_panic(|| { let res = catch_panic(|| {
let db_data = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_data = wallet_db(db_data, db_data_len, network)?;
if account >= 0 { if account >= 0 {
(&db_data) (&db_data)
.get_target_and_anchor_heights() .get_target_and_anchor_heights()
@ -730,11 +754,13 @@ pub extern "C" fn zcashlc_get_verified_transparent_balance(
db_data: *const u8, db_data: *const u8,
db_data_len: usize, db_data_len: usize,
address: *const c_char, address: *const c_char,
network_id: u32,
) -> i64 { ) -> i64 {
let res = catch_panic(|| { let res = catch_panic(|| {
let db_data = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_data = wallet_db(db_data, db_data_len, network)?;
let addr = unsafe { CStr::from_ptr(address).to_str()? }; let addr = unsafe { CStr::from_ptr(address).to_str()? };
let taddr = TransparentAddress::decode(&NETWORK, &addr).unwrap(); let taddr = TransparentAddress::decode(&network, &addr).unwrap();
let amount = (&db_data) let amount = (&db_data)
.get_target_and_anchor_heights() .get_target_and_anchor_heights()
.map_err(|e| format_err!("Error while fetching anchor height: {}", e)) .map_err(|e| format_err!("Error while fetching anchor height: {}", e))
@ -764,11 +790,13 @@ pub extern "C" fn zcashlc_get_total_transparent_balance(
db_data: *const u8, db_data: *const u8,
db_data_len: usize, db_data_len: usize,
address: *const c_char, address: *const c_char,
network_id: u32,
) -> i64 { ) -> i64 {
let res = catch_panic(|| { let res = catch_panic(|| {
let db_data = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_data = wallet_db(db_data, db_data_len, network)?;
let addr = unsafe { CStr::from_ptr(address).to_str()? }; let addr = unsafe { CStr::from_ptr(address).to_str()? };
let taddr = TransparentAddress::decode(&NETWORK, &addr).unwrap(); let taddr = TransparentAddress::decode(&network, &addr).unwrap();
let amount = (&db_data) let amount = (&db_data)
.get_target_and_anchor_heights() .get_target_and_anchor_heights()
.map_err(|e| format_err!("Error while fetching anchor height: {}", e)) .map_err(|e| format_err!("Error while fetching anchor height: {}", e))
@ -803,9 +831,11 @@ pub extern "C" fn zcashlc_get_received_memo_as_utf8(
db_data: *const u8, db_data: *const u8,
db_data_len: usize, db_data_len: usize,
id_note: i64, id_note: i64,
network_id: u32,
) -> *mut c_char { ) -> *mut c_char {
let res = catch_panic(|| { let res = catch_panic(|| {
let db_data = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_data = wallet_db(db_data, db_data_len, network)?;
let memo = (&db_data).get_memo(NoteId::ReceivedNoteId(id_note)) let memo = (&db_data).get_memo(NoteId::ReceivedNoteId(id_note))
.map_err(|e| format_err!("An error occurred retrieving the memo, {}", e)) .map_err(|e| format_err!("An error occurred retrieving the memo, {}", e))
@ -833,9 +863,11 @@ pub extern "C" fn zcashlc_get_sent_memo_as_utf8(
db_data: *const u8, db_data: *const u8,
db_data_len: usize, db_data_len: usize,
id_note: i64, id_note: i64,
network_id: u32,
) -> *mut c_char { ) -> *mut c_char {
let res = catch_panic(|| { let res = catch_panic(|| {
let db_data = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_data = wallet_db(db_data, db_data_len, network)?;
let memo = (&db_data).get_memo(NoteId::SentNoteId(id_note)) let memo = (&db_data).get_memo(NoteId::SentNoteId(id_note))
.map_err(|e| format_err!("An error occurred retrieving the memo, {}", e)) .map_err(|e| format_err!("An error occurred retrieving the memo, {}", e))
@ -874,16 +906,18 @@ pub extern "C" fn zcashlc_validate_combined_chain(
db_cache_len: usize, db_cache_len: usize,
db_data: *const u8, db_data: *const u8,
db_data_len: usize, db_data_len: usize,
network_id: u32,
) -> i32 { ) -> i32 {
let res = catch_panic(|| { let res = catch_panic(|| {
let network = parse_network(network_id)?;
let block_db = block_db(db_cache, db_cache_len)?; let block_db = block_db(db_cache, db_cache_len)?;
let db_data = wallet_db(db_data, db_data_len)?; let db_data = wallet_db(db_data, db_data_len, network)?;
let validate_from = (&db_data) let validate_from = (&db_data)
.get_max_height_hash() .get_max_height_hash()
.map_err(|e| format_err!("Error while validating chain: {}", e))?; .map_err(|e| format_err!("Error while validating chain: {}", e))?;
let val_res = validate_chain(&NETWORK, &block_db, validate_from); let val_res = validate_chain(&network, &block_db, validate_from);
if let Err(e) = val_res { if let Err(e) = val_res {
match e { match e {
@ -905,12 +939,14 @@ pub extern "C" fn zcashlc_get_nearest_rewind_height(
db_data: *const u8, db_data: *const u8,
db_data_len: usize, db_data_len: usize,
height: i32, height: i32,
network_id: u32,
) -> i32 { ) -> i32 {
let res = catch_panic(|| { let res = catch_panic(|| {
if height < 100 { if height < 100 {
Ok(height) Ok(height)
} else { } else {
let db_data = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_data = wallet_db(db_data, db_data_len, network)?;
let height = BlockHeight::try_from(height)?; let height = BlockHeight::try_from(height)?;
match get_rewind_height(&db_data) { match get_rewind_height(&db_data) {
Ok(Some(best_height)) => { Ok(Some(best_height)) => {
@ -937,9 +973,11 @@ pub extern "C" fn zcashlc_rewind_to_height(
db_data: *const u8, db_data: *const u8,
db_data_len: usize, db_data_len: usize,
height: i32, height: i32,
network_id: u32,
) -> bool { ) -> bool {
let res = catch_panic(|| { let res = catch_panic(|| {
let db_data = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_data = wallet_db(db_data, db_data_len, network)?;
let height = BlockHeight::try_from(height)?; let height = BlockHeight::try_from(height)?;
rewind_to_height(&db_data, height) rewind_to_height(&db_data, height)
@ -970,17 +1008,19 @@ pub extern "C" fn zcashlc_scan_blocks(
db_data: *const u8, db_data: *const u8,
db_data_len: usize, db_data_len: usize,
scan_limit: u32, scan_limit: u32,
network_id: u32,
) -> i32 { ) -> i32 {
let res = catch_panic(|| { let res = catch_panic(|| {
let network = parse_network(network_id)?;
let block_db = block_db(db_cache, db_cache_len)?; let block_db = block_db(db_cache, db_cache_len)?;
let db_read = wallet_db(db_data, db_data_len)?; let db_read = wallet_db(db_data, db_data_len, network)?;
let mut db_data = db_read.get_update_ops()?; let mut db_data = db_read.get_update_ops()?;
let limit = if scan_limit <= 0 { let limit = if scan_limit <= 0 {
None None
} else { } else {
Some(scan_limit) Some(scan_limit)
}; };
match scan_cached_blocks(&NETWORK, &block_db, &mut db_data, limit) { match scan_cached_blocks(&network, &block_db, &mut db_data, limit) {
Ok(()) => Ok(1), Ok(()) => Ok(1),
Err(e) => Err(format_err!("Error while scanning blocks: {}", e)), Err(e) => Err(format_err!("Error while scanning blocks: {}", e)),
} }
@ -1000,9 +1040,11 @@ pub extern "C" fn zcashlc_put_utxo(
script_bytes_len: usize, script_bytes_len: usize,
value: i64, value: i64,
height: i32, height: i32,
network_id: u32,
) -> bool { ) -> bool {
let res = catch_panic(|| { let res = catch_panic(|| {
let db_data = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_data = wallet_db(db_data, db_data_len, network)?;
let mut db_data = db_data.get_update_ops()?; let mut db_data = db_data.get_update_ops()?;
let addr = unsafe { CStr::from_ptr(address_str).to_str()? }; let addr = unsafe { CStr::from_ptr(address_str).to_str()? };
@ -1013,7 +1055,7 @@ pub extern "C" fn zcashlc_put_utxo(
let script_bytes = unsafe { slice::from_raw_parts(script_bytes, script_bytes_len) }; let script_bytes = unsafe { slice::from_raw_parts(script_bytes, script_bytes_len) };
let script = script_bytes.to_vec(); let script = script_bytes.to_vec();
let address = TransparentAddress::decode(&NETWORK, &addr).unwrap(); let address = TransparentAddress::decode(&network, &addr).unwrap();
let output = WalletTransparentOutput { let output = WalletTransparentOutput {
address: address, address: address,
@ -1036,12 +1078,14 @@ pub unsafe extern "C" fn zcashlc_clear_utxos(
db_data_len: usize, db_data_len: usize,
taddress: *const c_char, taddress: *const c_char,
above_height: i32, above_height: i32,
network_id: u32,
) -> i32 { ) -> i32 {
let res = catch_panic(|| { let res = catch_panic(|| {
let db_data = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_data = wallet_db(db_data, db_data_len, network)?;
let mut db_data = db_data.get_update_ops()?; let mut db_data = db_data.get_update_ops()?;
let addr = CStr::from_ptr(taddress).to_str()?; let addr = CStr::from_ptr(taddress).to_str()?;
let taddress = TransparentAddress::decode(&NETWORK, &addr).unwrap(); let taddress = TransparentAddress::decode(&network, &addr).unwrap();
let height = BlockHeight::from(above_height as u32); let height = BlockHeight::from(above_height as u32);
match delete_utxos_above(&mut db_data, &taddress, height) { match delete_utxos_above(&mut db_data, &taddress, height) {
Ok(rows) => Ok(rows as i32), Ok(rows) => Ok(rows as i32),
@ -1057,14 +1101,16 @@ pub extern "C" fn zcashlc_decrypt_and_store_transaction(
db_data_len: usize, db_data_len: usize,
tx: *const u8, tx: *const u8,
tx_len: usize, tx_len: usize,
network_id: u32,
) -> i32 { ) -> i32 {
let res = catch_panic(|| { let res = catch_panic(|| {
let db_read = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_read = wallet_db(db_data, db_data_len, network)?;
let mut db_data = db_read.get_update_ops()?; let mut db_data = db_read.get_update_ops()?;
let tx_bytes = unsafe { slice::from_raw_parts(tx, tx_len) }; let tx_bytes = unsafe { slice::from_raw_parts(tx, tx_len) };
let tx = Transaction::read(&tx_bytes[..])?; let tx = Transaction::read(&tx_bytes[..])?;
match decrypt_and_store_transaction(&NETWORK, &mut db_data, &tx) { match decrypt_and_store_transaction(&network, &mut db_data, &tx) {
Ok(()) => Ok(1), Ok(()) => Ok(1),
Err(e) => Err(format_err!("Error while decrypting transaction: {}", e)), Err(e) => Err(format_err!("Error while decrypting transaction: {}", e)),
} }
@ -1093,9 +1139,11 @@ pub extern "C" fn zcashlc_create_to_address(
spend_params_len: usize, spend_params_len: usize,
output_params: *const u8, output_params: *const u8,
output_params_len: usize, output_params_len: usize,
network_id: u32,
) -> i64 { ) -> i64 {
let res = catch_panic(|| { let res = catch_panic(|| {
let db_read = wallet_db(db_data, db_data_len)?; let network = parse_network(network_id)?;
let db_read = wallet_db(db_data, db_data_len, network)?;
let mut db_data = db_read.get_update_ops()?; let mut db_data = db_read.get_update_ops()?;
let account = if account >= 0 { let account = if account >= 0 {
account as u32 account as u32
@ -1118,7 +1166,7 @@ pub extern "C" fn zcashlc_create_to_address(
})); }));
let extsk = let extsk =
match decode_extended_spending_key(NETWORK.hrp_sapling_extended_spending_key(), &extsk) match decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), &extsk)
{ {
Ok(Some(extsk)) => extsk, Ok(Some(extsk)) => extsk,
Ok(None) => { Ok(None) => {
@ -1129,7 +1177,7 @@ pub extern "C" fn zcashlc_create_to_address(
} }
}; };
let to = match RecipientAddress::decode(&NETWORK, &to) { let to = match RecipientAddress::decode(&network, &to) {
Some(to) => to, Some(to) => to,
None => { None => {
return Err(format_err!("PaymentAddress is for the wrong network")); return Err(format_err!("PaymentAddress is for the wrong network"));
@ -1149,7 +1197,7 @@ pub extern "C" fn zcashlc_create_to_address(
create_spend_to_address( create_spend_to_address(
&mut db_data, &mut db_data,
&NETWORK, &network,
prover, prover,
AccountId(account), AccountId(account),
&extsk, &extsk,
@ -1164,9 +1212,13 @@ pub extern "C" fn zcashlc_create_to_address(
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn zcashlc_branch_id_for_height(height: i32) -> i32 { pub extern "C" fn zcashlc_branch_id_for_height(
height: i32,
network_id: u32,
) -> i32 {
let res = catch_panic(|| { let res = catch_panic(|| {
let branch: BranchId = BranchId::for_height(&NETWORK, BlockHeight::from(height as u32)); let network = parse_network(network_id)?;
let branch: BranchId = BranchId::for_height(&network, BlockHeight::from(height as u32));
let branch_id: u32 = u32::from(branch); let branch_id: u32 = u32::from(branch);
Ok(branch_id as i32) Ok(branch_id as i32)
}); });
@ -1209,9 +1261,10 @@ pub unsafe extern "C" fn zcashlc_derive_transparent_private_key_from_seed(
seed_len: usize, seed_len: usize,
account: i32, account: i32,
index: i32, index: i32,
network_id: u32,
) -> *mut c_char { ) -> *mut c_char {
let res = catch_panic(|| { let res = catch_panic(|| {
let network = parse_network(network_id)?;
let seed = slice::from_raw_parts(seed, seed_len); let seed = slice::from_raw_parts(seed, seed_len);
let account = if account >= 0 { let account = if account >= 0 {
account as u32 account as u32
@ -1224,7 +1277,7 @@ pub unsafe extern "C" fn zcashlc_derive_transparent_private_key_from_seed(
} else { } else {
return Err(format_err!("index argument must be positive")); return Err(format_err!("index argument must be positive"));
}; };
let sk = derive_secret_key_from_seed(&NETWORK, &seed, AccountId(account), index).unwrap(); let sk = derive_secret_key_from_seed(&network, &seed, AccountId(account), index).unwrap();
let sk_wif = Wif::from_secret_key(&sk, true); let sk_wif = Wif::from_secret_key(&sk, true);
Ok(CString::new(sk_wif.0.to_string()).unwrap().into_raw()) Ok(CString::new(sk_wif.0.to_string()).unwrap().into_raw())
@ -1239,9 +1292,11 @@ pub unsafe extern "C" fn zcashlc_derive_transparent_address_from_seed(
seed_len: usize, seed_len: usize,
account: i32, account: i32,
index: i32, index: i32,
network_id: u32,
) -> *mut c_char { ) -> *mut c_char {
let res = catch_panic(|| { let res = catch_panic(|| {
let seed = slice::from_raw_parts(seed, seed_len); let seed = slice::from_raw_parts(seed, seed_len);
let network = parse_network(network_id)?;
let account = if account >= 0 { let account = if account >= 0 {
account as u32 account as u32
} else { } else {
@ -1253,9 +1308,9 @@ pub unsafe extern "C" fn zcashlc_derive_transparent_address_from_seed(
} else { } else {
return Err(format_err!("index argument must be positive")); return Err(format_err!("index argument must be positive"));
}; };
let sk = derive_secret_key_from_seed(&NETWORK, &seed, AccountId(account), index); let sk = derive_secret_key_from_seed(&network, &seed, AccountId(account), index);
let taddr = derive_transparent_address_from_secret_key(&sk.unwrap()) let taddr = derive_transparent_address_from_secret_key(&sk.unwrap())
.encode(&NETWORK); .encode(&network);
Ok(CString::new(taddr).unwrap().into_raw()) Ok(CString::new(taddr).unwrap().into_raw())
}); });
@ -1266,9 +1321,10 @@ pub unsafe extern "C" fn zcashlc_derive_transparent_address_from_seed(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn zcashlc_derive_transparent_address_from_secret_key( pub unsafe extern "C" fn zcashlc_derive_transparent_address_from_secret_key(
tsk: *const c_char, tsk: *const c_char,
network_id: u32,
) -> *mut c_char { ) -> *mut c_char {
let res = catch_panic(|| { let res = catch_panic(|| {
let network = parse_network(network_id)?;
let tsk_wif = CStr::from_ptr(tsk).to_str()?; let tsk_wif = CStr::from_ptr(tsk).to_str()?;
let sk: SecretKey = (&Wif(tsk_wif.to_string())).try_into().expect("invalid private key WIF"); let sk: SecretKey = (&Wif(tsk_wif.to_string())).try_into().expect("invalid private key WIF");
@ -1276,12 +1332,91 @@ pub unsafe extern "C" fn zcashlc_derive_transparent_address_from_secret_key(
// derive the corresponding t-address // derive the corresponding t-address
let taddr = let taddr =
derive_transparent_address_from_secret_key(&sk) derive_transparent_address_from_secret_key(&sk)
.encode(&NETWORK); .encode(&network);
Ok(CString::new(taddr).unwrap().into_raw()) Ok(CString::new(taddr).unwrap().into_raw())
}); });
unwrap_exc_or_null(res) unwrap_exc_or_null(res)
} }
#[no_mangle]
pub extern "C" fn zcashlc_shield_funds(
db_data: *const u8,
db_data_len: usize,
account: i32,
tsk: *const c_char,
extsk: *const c_char,
memo: *const c_char,
spend_params: *const u8,
spend_params_len: usize,
output_params: *const u8,
output_params_len: usize,
network_id: u32,
) -> i64 {
let res = catch_panic(|| {
let network = parse_network(network_id)?;
let db_data = wallet_db(db_data, db_data_len, network)?;
let mut update_ops = (&db_data)
.get_update_ops()
.map_err(|e| format_err!("Could not obtain a writable database connection: {}", e))?;
let account = if account >= 0 {
account as u32
} else {
return Err(format_err!("account argument must be positive"));
};
let tsk_wif = unsafe { CStr::from_ptr(tsk) }.to_str()?;
let extsk = unsafe { CStr::from_ptr(extsk) }.to_str()?;
let memo = unsafe { CStr::from_ptr(memo) }.to_str()?;
let spend_params = Path::new(OsStr::from_bytes(unsafe {
slice::from_raw_parts(spend_params, spend_params_len)
}));
let output_params = Path::new(OsStr::from_bytes(unsafe {
slice::from_raw_parts(output_params, output_params_len)
}));
//grab secret private key for t-funds
let sk:SecretKey = (&Wif(tsk_wif.to_string())).try_into()?;
let extsk =
match decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), &extsk)
{
Ok(Some(extsk)) => extsk,
Ok(None) => {
return Err(format_err!("ExtendedSpendingKey is for the wrong network"));
},
Err(e) => {
return Err(format_err!("Invalid ExtendedSpendingKey: {}", e));
},
};
let memo = Memo::from_str(&memo).map_err(|_| format_err!("Invalid memo"))?;
let memo_bytes = MemoBytes::from(memo);
// shield_funds(&db_cache, &db_data, account, &tsk, &extsk, &memo, &spend_params, &output_params)
shield_funds(&mut update_ops,
&network,
LocalTxProver::new(spend_params, output_params),
AccountId(account),
&sk,
&extsk,
&memo_bytes,
0) // fix off-by-one error. 10 confs already added in this function
.map_err(|e| format_err!("Error while shielding transaction: {}", e))
});
unwrap_exc_or(res, -1)
}
//
// Utility functions
//
fn parse_network(value: u32) -> Result<Network, failure::Error> {
match value {
0 => Ok(TestNetwork),
1 => Ok(MainNetwork),
_ => Err(format_err!("Invalid network type: {}. Expected either 0 or 1 for Testnet or Mainnet, respectively.", value))
}
}
// //
// Helper code from: https://github.com/adityapk00/zecwallet-light-cli/blob/master/lib/src/lightwallet.rs // Helper code from: https://github.com/adityapk00/zecwallet-light-cli/blob/master/lib/src/lightwallet.rs
// //
@ -1310,70 +1445,4 @@ pub fn double_sha256(payload: &[u8]) -> Vec<u8> {
let h1 = Sha256::digest(&payload); let h1 = Sha256::digest(&payload);
let h2 = Sha256::digest(&h1); let h2 = Sha256::digest(&h1);
h2.to_vec() h2.to_vec()
} }
#[no_mangle]
pub extern "C" fn zcashlc_shield_funds(
db_data: *const u8,
db_data_len: usize,
account: i32,
tsk: *const c_char,
extsk: *const c_char,
memo: *const c_char,
spend_params: *const u8,
spend_params_len: usize,
output_params: *const u8,
output_params_len: usize,
) -> i64 {
let res = catch_panic(|| {
let db_data = wallet_db(db_data, db_data_len)?;
let mut update_ops = (&db_data)
.get_update_ops()
.map_err(|e| format_err!("Could not obtain a writable database connection: {}", e))?;
let account = if account >= 0 {
account as u32
} else {
return Err(format_err!("account argument must be positive"));
};
let tsk_wif = unsafe { CStr::from_ptr(tsk) }.to_str()?;
let extsk = unsafe { CStr::from_ptr(extsk) }.to_str()?;
let memo = unsafe { CStr::from_ptr(memo) }.to_str()?;
let spend_params = Path::new(OsStr::from_bytes(unsafe {
slice::from_raw_parts(spend_params, spend_params_len)
}));
let output_params = Path::new(OsStr::from_bytes(unsafe {
slice::from_raw_parts(output_params, output_params_len)
}));
//grab secret private key for t-funds
let sk:SecretKey = (&Wif(tsk_wif.to_string())).try_into()?;
let extsk =
match decode_extended_spending_key(NETWORK.hrp_sapling_extended_spending_key(), &extsk)
{
Ok(Some(extsk)) => extsk,
Ok(None) => {
return Err(format_err!("ExtendedSpendingKey is for the wrong network"));
},
Err(e) => {
return Err(format_err!("Invalid ExtendedSpendingKey: {}", e));
},
};
let memo = Memo::from_str(&memo).map_err(|_| format_err!("Invalid memo"))?;
let memo_bytes = MemoBytes::from(memo);
// shield_funds(&db_cache, &db_data, account, &tsk, &extsk, &memo, &spend_params, &output_params)
shield_funds(&mut update_ops,
&NETWORK,
LocalTxProver::new(spend_params, output_params),
AccountId(account),
&sk,
&extsk,
&memo_bytes,
ANCHOR_OFFSET)
.map_err(|e| format_err!("Error while shielding transaction: {}", e))
});
unwrap_exc_or(res, -1)
}