[#398] Make WalletBirthday an internal type (#414)

This commit makes Renames `WalletBirthday` to `Checkpoint` and
makes Checkpoint an internal type. Public ocurrences of this
type is replaced by `BlockHeight` (Int) and then retrieval of the
Checkpoint is deferred to the appropiate place in the code

Add an extension method to `BlockHeight` to get latest checkpoint
height present in the SDK's bundle

PR Suggestions:

Add test for integer overflow on JSON
File renamed from WalletBirthday to Checkpoint
This commit is contained in:
Francisco Gindre 2022-07-12 16:36:12 -03:00 committed by GitHub
parent aff3a9563b
commit 2fcfa6fdbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 152 additions and 134 deletions

View File

@ -403,7 +403,10 @@ public class CompactBlockProcessor {
config: Configuration( config: Configuration(
cacheDb: initializer.cacheDbURL, cacheDb: initializer.cacheDbURL,
dataDb: initializer.dataDbURL, dataDb: initializer.dataDbURL,
walletBirthday: initializer.walletBirthday.height, walletBirthday: Checkpoint.birthday(
with: initializer.walletBirthday,
network: initializer.network
).height,
network: initializer.network network: initializer.network
), ),
repository: initializer.transactionRepository, repository: initializer.transactionRepository,

View File

@ -7,8 +7,8 @@
import Foundation import Foundation
public extension WalletBirthday { extension Checkpoint {
static func birthday(with height: BlockHeight, network: ZcashNetwork) -> WalletBirthday { static func birthday(with height: BlockHeight, network: ZcashNetwork) -> Checkpoint {
let checkpointDirectoryURL = BundleCheckpointURLProvider.default.url(network.networkType) let checkpointDirectoryURL = BundleCheckpointURLProvider.default.url(network.networkType)
switch network.networkType { switch network.networkType {
@ -20,8 +20,8 @@ public extension WalletBirthday {
} }
} }
extension WalletBirthday { extension Checkpoint {
static func birthday(with height: BlockHeight, checkpointDirectory: URL) -> WalletBirthday? { static func birthday(with height: BlockHeight, checkpointDirectory: URL) -> Checkpoint? {
return bestCheckpointHeight(for: height, checkpointDirectory: checkpointDirectory) return bestCheckpointHeight(for: height, checkpointDirectory: checkpointDirectory)
.flatMap { checkpoint(height: $0, directory: checkpointDirectory) } .flatMap { checkpoint(height: $0, directory: checkpointDirectory) }
} }
@ -44,7 +44,7 @@ extension WalletBirthday {
.last .last
} }
private static func checkpoint(height: BlockHeight, directory checkpointDirectory: URL) -> WalletBirthday? { private static func checkpoint(height: BlockHeight, directory checkpointDirectory: URL) -> Checkpoint? {
let url = checkpointDirectory let url = checkpointDirectory
.appendingPathComponent(String(height)) .appendingPathComponent(String(height))
.appendingPathExtension("json") .appendingPathExtension("json")
@ -52,9 +52,9 @@ extension WalletBirthday {
return try? checkpoint(at: url) return try? checkpoint(at: url)
} }
private static func checkpoint(at url: URL) throws -> WalletBirthday { private static func checkpoint(at url: URL) throws -> Checkpoint {
let data = try Data(contentsOf: url) let data = try Data(contentsOf: url)
let checkpoint = try JSONDecoder().decode(WalletBirthday.self, from: data) let checkpoint = try JSONDecoder().decode(Checkpoint.self, from: data)
return checkpoint return checkpoint
} }
} }
@ -79,9 +79,9 @@ extension BundleCheckpointURLProvider {
static var iOS = BundleCheckpointURLProvider(url: { networkType in static var iOS = BundleCheckpointURLProvider(url: { networkType in
switch networkType { switch networkType {
case .mainnet: case .mainnet:
return WalletBirthday.mainnetCheckpointDirectory return Checkpoint.mainnetCheckpointDirectory
case .testnet: case .testnet:
return WalletBirthday.testnetCheckpointDirectory return Checkpoint.testnetCheckpointDirectory
} }
}) })
@ -99,7 +99,7 @@ extension BundleCheckpointURLProvider {
subdirectory: "checkpoints/mainnet/", subdirectory: "checkpoints/mainnet/",
localization: nil localization: nil
)? )?
.deletingLastPathComponent() ?? WalletBirthday.mainnetCheckpointDirectory .deletingLastPathComponent() ?? Checkpoint.mainnetCheckpointDirectory
case .testnet: case .testnet:
return Bundle.module.url( return Bundle.module.url(
forResource: "280000", forResource: "280000",
@ -107,7 +107,7 @@ extension BundleCheckpointURLProvider {
subdirectory: "checkpoints/testnet/", subdirectory: "checkpoints/testnet/",
localization: nil localization: nil
)? )?
.deletingLastPathComponent() ?? WalletBirthday.testnetCheckpointDirectory .deletingLastPathComponent() ?? Checkpoint.testnetCheckpointDirectory
} }
}) })
} }

View File

@ -6,8 +6,8 @@
// //
import Foundation import Foundation
extension WalletBirthday { extension Checkpoint {
static let mainnetMin = WalletBirthday( static let mainnetMin = Checkpoint(
height: 419_200, height: 419_200,
hash: "00000000025a57200d898ac7f21e26bf29028bbe96ec46e05b2c17cc9db9e4f3", hash: "00000000025a57200d898ac7f21e26bf29028bbe96ec46e05b2c17cc9db9e4f3",
time: 1540779337, time: 1540779337,

View File

@ -7,8 +7,8 @@
import Foundation import Foundation
extension WalletBirthday { extension Checkpoint {
static let testnetMin = WalletBirthday( static let testnetMin = Checkpoint(
height: 280000, height: 280000,
hash: "000420e7fcc3a49d729479fb0b560dd7b8617b178a08e9e389620a9d1dd6361a", hash: "000420e7fcc3a49d729479fb0b560dd7b8617b178a08e9e389620a9d1dd6361a",
time: 1535262293, time: 1535262293,
@ -16,5 +16,4 @@ extension WalletBirthday {
) )
static let testnetCheckpointDirectory = Bundle.module.bundleURL.appendingPathComponent("checkpoints/testnet/") static let testnetCheckpointDirectory = Bundle.module.bundleURL.appendingPathComponent("checkpoints/testnet/")
} }

View File

@ -78,7 +78,7 @@ public class Initializer {
private(set) var downloader: CompactBlockDownloader private(set) var downloader: CompactBlockDownloader
private(set) var network: ZcashNetwork 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: BlockHeight
/** /**
Constructs the Initializer Constructs the Initializer
@ -168,7 +168,7 @@ 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, network: network) self.walletBirthday = walletBirthday
self.network = network self.network = network
} }
@ -202,12 +202,13 @@ public class Initializer {
} }
do { do {
let checkpoint = Checkpoint.birthday(with: self.walletBirthday, network: network)
try rustBackend.initBlocksTable( try rustBackend.initBlocksTable(
dbData: dataDbURL, dbData: dataDbURL,
height: Int32(walletBirthday.height), height: Int32(checkpoint.height),
hash: walletBirthday.hash, hash: checkpoint.hash,
time: walletBirthday.time, time: checkpoint.time,
saplingTree: walletBirthday.saplingTree, saplingTree: checkpoint.saplingTree,
networkType: network.networkType networkType: network.networkType
) )
} catch RustWeldingError.dataDbNotEmpty { } catch RustWeldingError.dataDbNotEmpty {
@ -216,9 +217,9 @@ public class Initializer {
throw InitializerError.dataDbInitFailed throw InitializerError.dataDbInitFailed
} }
let lastDownloaded = (try? downloader.storage.latestHeight()) ?? walletBirthday.height let lastDownloaded = (try? downloader.storage.latestHeight()) ?? walletBirthday
// resume from last downloaded block // resume from last downloaded block
lowerBoundHeight = max(walletBirthday.height, lastDownloaded) lowerBoundHeight = max(walletBirthday, lastDownloaded)
do { do {
guard try rustBackend.initAccountsTable( guard try rustBackend.initAccountsTable(

View File

@ -0,0 +1,80 @@
//
// Checkpoint.swift
//
//
// Created by Francisco Gindre on 7/12/22.
//
import Foundation
/// Represents the wallet's birthday which can be thought of as a checkpoint at the earliest moment in history where
/// transactions related to this wallet could exist. Ideally, this would correspond to the latest block height at the
/// time the wallet key was created. Worst case, the height of Sapling activation could be used (280000).
///
/// Knowing a wallet's birthday can significantly reduce the amount of data that it needs to download because none of
/// the data before that height needs to be scanned for transactions. However, we do need the Sapling tree data in
/// order to construct valid transactions from that point forward. This birthday contains that tree data, allowing us
/// to avoid downloading all the compact blocks required in order to generate it.
///
/// New wallets can ignore any blocks created before their birthday.
///
/// - Parameters:
/// - height: the height at the time the wallet was born
/// - hash: the block hash corresponding to the given height
/// - time: the time the wallet was born, in seconds
/// - saplingTree: the sapling tree corresponding to the given height. This takes around 15 minutes of processing to generate from scratch because all blocks since activation need to be considered. So when it is calculated in advance it can save the user a lot of time.
/// - orchardTree: the orchard tree corresponding to the given height. This field is optional since it won't be available prior
/// to NU5 activation height for the given network.
struct Checkpoint: Equatable {
private(set) var height: BlockHeight
private(set) var hash: String
private(set) var time: UInt32
private(set) var saplingTree: String
private(set) var orchardTree: String?
}
extension Checkpoint: Decodable {
public enum CodingKeys: String, CodingKey {
case height
case hash
case time
case saplingTree
case orchardTree
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.height = try Self.getHeight(from: container)
self.hash = try container.decode(String.self, forKey: .hash)
self.time = try container.decode(UInt32.self, forKey: .time)
self.saplingTree = try container.decode(String.self, forKey: .saplingTree)
self.orchardTree = try container.decodeIfPresent(String.self, forKey: .orchardTree)
}
static func getHeight(from container: KeyedDecodingContainer<CodingKeys>) throws -> Int {
guard
let heightString = try? container.decode(String.self, forKey: .height),
let height = Int(heightString)
else {
throw DecodingError.typeMismatch(
String.self,
DecodingError.Context(
codingPath: [CodingKeys.height],
debugDescription: "expected height to be encoded as a string",
underlyingError: nil
)
)
}
return height
}
}
public extension BlockHeight {
/// Useful when creating a new wallet to reduce sync times.
/// - Parameters:
/// - zcashNetwork: Network to use for the block height.
/// - Returns: The block height of the newest checkpoint known by the SDK.
static func ofLatestCheckpoint(network: ZcashNetwork) -> BlockHeight {
Checkpoint.birthday(with: BlockHeight.max, network: network).height
}
}

View File

@ -1,89 +1,10 @@
// //
// WalletTypes.swift // WalletTypes.swift
// Pods //
// //
// Created by Francisco Gindre on 4/6/21. // Created by Francisco Gindre on 4/6/21.
// //
/// Represents the wallet's birthday which can be thought of as a checkpoint at the earliest moment in history where
/// transactions related to this wallet could exist. Ideally, this would correspond to the latest block height at the
/// time the wallet key was created. Worst case, the height of Sapling activation could be used (280000).
///
/// Knowing a wallet's birthday can significantly reduce the amount of data that it needs to download because none of
/// the data before that height needs to be scanned for transactions. However, we do need the Sapling tree data in
/// order to construct valid transactions from that point forward. This birthday contains that tree data, allowing us
/// to avoid downloading all the compact blocks required in order to generate it.
///
/// New wallets can ignore any blocks created before their birthday.
///
/// - Parameters:
/// - height: the height at the time the wallet was born
/// - hash: the block hash corresponding to the given height
/// - time: the time the wallet was born, in seconds
/// - saplingTree: the sapling tree corresponding to the given height. This takes around 15 minutes of processing to generate from scratch because all blocks since activation need to be considered. So when it is calculated in advance it can save the user a lot of time.
/// - orchardTree: the orchard tree corresponding to the given height. This field is optional since it won't be available prior
/// to NU5 activation height for the given network.
public struct WalletBirthday: Equatable {
public private(set) var height: BlockHeight = -1
public private(set) var hash: String = ""
public private(set) var time: UInt32 = 0
public private(set) var saplingTree: String = ""
public private(set) var orchardTree: String?
}
extension WalletBirthday: Decodable {
// let height: BlockHeight
// let hash: String
// let time: UInt32
// let saplingTree: String
// let orchardTree: String?
// func walletBirthday() -> WalletBirthday {
// WalletBirthday(
// height: height,
// hash: hash,
// time: time,
// tree: tree
// )
// }
public enum CodingKeys: String, CodingKey {
case height
case hash
case time
case saplingTree
case orchardTree
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.height = try Self.getHeight(from: container)
self.hash = try container.decode(String.self, forKey: .hash)
self.time = try container.decode(UInt32.self, forKey: .time)
self.saplingTree = try container.decode(String.self, forKey: .saplingTree)
self.orchardTree = try container.decodeIfPresent(String.self, forKey: .orchardTree)
}
static func getHeight(from container: KeyedDecodingContainer<CodingKeys>) throws -> Int {
guard
let heightString = try? container.decode(String.self, forKey: .height),
let height = Int(heightString)
else {
throw DecodingError.typeMismatch(
String.self,
DecodingError.Context(
codingPath: [CodingKeys.height],
debugDescription: "expected height to be encoded as a string",
underlyingError: nil
)
)
}
return height
}
}
/** /**
Groups a Sapling Extended Full Viewing Key an a tranparent address extended public key. Groups a Sapling Extended Full Viewing Key an a tranparent address extended public key.
*/ */

View File

@ -137,7 +137,7 @@ public class SDKSynchronizer: Synchronizer {
self.transactionRepository = transactionRepository self.transactionRepository = transactionRepository
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
self.network = initializer.network self.network = initializer.network
self.subscribeToProcessorNotifications(blockProcessor) self.subscribeToProcessorNotifications(blockProcessor)
} }
@ -149,12 +149,12 @@ public class SDKSynchronizer: Synchronizer {
public func initialize() throws { public func initialize() throws {
try self.initializer.initialize() try self.initializer.initialize()
try self.blockProcessor.setStartHeight(initializer.walletBirthday.height) try self.blockProcessor.setStartHeight(initializer.walletBirthday)
} }
public func prepare() throws { public func prepare() throws {
try self.initializer.initialize() try self.initializer.initialize()
try self.blockProcessor.setStartHeight(initializer.walletBirthday.height) try self.blockProcessor.setStartHeight(initializer.walletBirthday)
self.status = .disconnected self.status = .disconnected
} }

View File

@ -88,7 +88,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, network: network).height let walletBirthday = Checkpoint.birthday(with: 663150, network: network).height
try basicReOrgTest( try basicReOrgTest(
baseDataset: .beforeReOrg, baseDataset: .beforeReOrg,
@ -104,7 +104,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), network: network).height let walletBirthday = Checkpoint.birthday(with: BlockHeight(663150), network: network).height
try basicReOrgTest( try basicReOrgTest(
baseDataset: .beforeReOrg, baseDataset: .beforeReOrg,

View File

@ -54,7 +54,7 @@ class TransactionEnhancementTests: XCTestCase {
waitExpectation = XCTestExpectation(description: "\(self.description) waitExpectation") waitExpectation = XCTestExpectation(description: "\(self.description) waitExpectation")
let birthday = WalletBirthday.birthday(with: walletBirthday, network: network) let birthday = Checkpoint.birthday(with: walletBirthday, network: network)
let config = CompactBlockProcessor.Configuration.standard(for: self.network, walletBirthday: birthday.height) let config = CompactBlockProcessor.Configuration.standard(for: self.network, walletBirthday: birthday.height)
let rustBackend = ZcashRustBackend.self let rustBackend = ZcashRustBackend.self
@ -125,7 +125,7 @@ class TransactionEnhancementTests: XCTestCase {
func testBasicEnhacement() throws { func testBasicEnhacement() throws {
let targetLatestHeight = BlockHeight(663250) let targetLatestHeight = BlockHeight(663250)
let walletBirthday = WalletBirthday.birthday(with: 663151, network: network).height let walletBirthday = Checkpoint.birthday(with: 663151, network: network).height
try basicEnhancementTest(latestHeight: targetLatestHeight, walletBirthday: walletBirthday) try basicEnhancementTest(latestHeight: targetLatestHeight, walletBirthday: walletBirthday)
} }

View File

@ -24,7 +24,7 @@ class BlockScanOperationTests: XCTestCase {
extpub: "02075a7f5f7507d64022dad5954849f216b0f1b09b2d588be663d8e7faeb5aaf61" extpub: "02075a7f5f7507d64022dad5954849f216b0f1b09b2d588be663d8e7faeb5aaf61"
) )
var walletBirthDay = WalletBirthday.birthday( var walletBirthDay = Checkpoint.birthday(
with: 1386000, with: 1386000,
network: ZcashNetworkBuilder.network(for: .testnet) network: ZcashNetworkBuilder.network(for: .testnet)
) )

View File

@ -3,12 +3,12 @@ import XCTest
class BirthdayTests: XCTestCase { class BirthdayTests: XCTestCase {
func test_BirthdayGetsMostRecentCheckpointBelowIt_Testnet() throws { func test_BirthdayGetsMostRecentCheckpointBelowIt_Testnet() throws {
let birthday = WalletBirthday.birthday( let birthday = Checkpoint.birthday(
with: 1530003, with: 1530003,
network: ZcashNetworkBuilder.network(for: .testnet) network: ZcashNetworkBuilder.network(for: .testnet)
) )
let expected = WalletBirthday( let expected = Checkpoint(
height: 1530000, height: 1530000,
hash: "0011f78082f26747e02f0ab3525dc34d8df8f69dde273f462fcbf08fe2aa14d6", hash: "0011f78082f26747e02f0ab3525dc34d8df8f69dde273f462fcbf08fe2aa14d6",
time: 1629030383, time: 1629030383,
@ -19,12 +19,12 @@ class BirthdayTests: XCTestCase {
} }
func test_BirthdayGetsMostRecentCheckpointBelowIt_Mainnet() throws { func test_BirthdayGetsMostRecentCheckpointBelowIt_Mainnet() throws {
let birthday = WalletBirthday.birthday( let birthday = Checkpoint.birthday(
with: 1340004, with: 1340004,
network: ZcashNetworkBuilder.network(for: .mainnet) network: ZcashNetworkBuilder.network(for: .mainnet)
) )
let expected = WalletBirthday( let expected = Checkpoint(
height: 1340000, height: 1340000,
hash: "00000000031bc547da975ebd77d9113b178053f88fb6a1d8511b4f8962c21c4b", hash: "00000000031bc547da975ebd77d9113b178053f88fb6a1d8511b4f8962c21c4b",
time: 1627846248, time: 1627846248,
@ -35,12 +35,12 @@ class BirthdayTests: XCTestCase {
} }
func test_startBirthdayIsGivenIfTooLow_Testnet() throws { func test_startBirthdayIsGivenIfTooLow_Testnet() throws {
let birthday = WalletBirthday.birthday( let birthday = Checkpoint.birthday(
with: 4, with: 4,
network: ZcashNetworkBuilder.network(for: .testnet) network: ZcashNetworkBuilder.network(for: .testnet)
) )
let expected = WalletBirthday( let expected = Checkpoint(
height: 280000, height: 280000,
hash: "000420e7fcc3a49d729479fb0b560dd7b8617b178a08e9e389620a9d1dd6361a", hash: "000420e7fcc3a49d729479fb0b560dd7b8617b178a08e9e389620a9d1dd6361a",
time: 1535262293, time: 1535262293,
@ -51,12 +51,12 @@ class BirthdayTests: XCTestCase {
} }
func test_startBirthdayIsGivenIfTooLow_Mainnet() throws { func test_startBirthdayIsGivenIfTooLow_Mainnet() throws {
let birthday = WalletBirthday.birthday( let birthday = Checkpoint.birthday(
with: 4, with: 4,
network: ZcashNetworkBuilder.network(for: .mainnet) network: ZcashNetworkBuilder.network(for: .mainnet)
) )
let expected = WalletBirthday( let expected = Checkpoint(
height: 419200, height: 419200,
hash: "00000000025a57200d898ac7f21e26bf29028bbe96ec46e05b2c17cc9db9e4f3", hash: "00000000025a57200d898ac7f21e26bf29028bbe96ec46e05b2c17cc9db9e4f3",
time: 1540779337, time: 1540779337,
@ -69,7 +69,7 @@ class BirthdayTests: XCTestCase {
func test_orchardTreeIsNotNilOnActivation_Mainnet() throws { func test_orchardTreeIsNotNilOnActivation_Mainnet() throws {
let activationHeight = 1687104 let activationHeight = 1687104
let birthday = WalletBirthday.birthday( let birthday = Checkpoint.birthday(
with: activationHeight, with: activationHeight,
network: ZcashNetworkBuilder.network(for: .mainnet) network: ZcashNetworkBuilder.network(for: .mainnet)
) )
@ -81,7 +81,7 @@ class BirthdayTests: XCTestCase {
func test_orchardTreeIsNilBeforeActivation_Mainnet() throws { func test_orchardTreeIsNilBeforeActivation_Mainnet() throws {
let activationHeight = 1_687_104 let activationHeight = 1_687_104
let birthday = WalletBirthday.birthday( let birthday = Checkpoint.birthday(
with: activationHeight - 1, with: activationHeight - 1,
network: ZcashNetworkBuilder.network(for: .mainnet) network: ZcashNetworkBuilder.network(for: .mainnet)
) )
@ -92,7 +92,7 @@ class BirthdayTests: XCTestCase {
func test_orchardTreeIsNotNilOnActivation_Testnet() throws { func test_orchardTreeIsNotNilOnActivation_Testnet() throws {
let activationHeight = 1_842_420 let activationHeight = 1_842_420
let birthday = WalletBirthday.birthday( let birthday = Checkpoint.birthday(
with: activationHeight, with: activationHeight,
network: ZcashNetworkBuilder.network(for: .testnet) network: ZcashNetworkBuilder.network(for: .testnet)
) )
@ -104,11 +104,31 @@ class BirthdayTests: XCTestCase {
func test_orchardTreeIsNilBeforeActivation_Testnet() throws { func test_orchardTreeIsNilBeforeActivation_Testnet() throws {
let activationHeight = 1687104 let activationHeight = 1687104
let birthday = WalletBirthday.birthday( let birthday = Checkpoint.birthday(
with: activationHeight - 1, with: activationHeight - 1,
network: ZcashNetworkBuilder.network(for: .testnet) network: ZcashNetworkBuilder.network(for: .testnet)
) )
XCTAssertNil(birthday.orchardTree) XCTAssertNil(birthday.orchardTree)
} }
func test_CheckpointParsingFailsIfIntegerOverflows() throws {
let jsonData = Self.integerOverflowJSON.data(using: .utf8)!
let decoder = JSONDecoder()
XCTAssertThrowsError(try decoder.decode(Checkpoint.self, from: jsonData))
}
/// this has height with `Int64.max + 1`
static let integerOverflowJSON: String =
"""
{
"network": "main",
"height": "9223372036854775808",
"hash": "0000000000aefe1d3aaa6908bd9fe99d476afd72ec49be60090d6ee48f9272bf",
"time": 1656499365,
"saplingTree": "0175848b81090fee135ed81677520ee555e72814ec47d77107779f1d958f72903001a5f61227d13a351d6b9744e572fbddfa60de77650f3b355838771ded6e929a401400000000016a6c28ea8d49d0b32f9c8fad56f239fd6f1dabd0eb2771d7877d4b3d714aee6b0001e4cf1a347436f1b700976cfa387833d3dd53eb3e9e7201d68d1fa15735db411e0140e3461535e2391a82f6cc29221432f53cdc62c697f36cd1077bc5c40bed2d230138cbb3e580d3292e0c783e8e37077be9a1e2c7c95cbc6a4a58cf6f51af755170012896f2157ea42af3ce58fa133917712564a148708702ba3dc5235e49ae36be15000001b9db8a4ba52f5cdea9d142ce71601c2890e9dc306018b4a730a9c8c0a7e258260000000134e093f073973de750e85daff57c07a102dbc7bbc77436e99b0074f36f1cbf130000015ec9e9b1295908beed437df4126032ca57ada8e3ebb67067cd22a73c79a84009",
"orchardTree": "01492e49f873e033c8baf296de1a78f34618d2ac1a64eca3769b93918da66e3f37001f000000018d8f2180ce6978074be7b5bec41e993232ac73797ca80ae32f062a5d83ee363c00000114764dc108e86dc2c6d7c20a6e1759027d87029b5dc7e1e6b5be970ecbed913a01186d95ac66b184f8844e57fece62a4d64cfeb73e7ed6e99146e79aacae7f5e00012f9cd86767aea1f11147f65c588f94dce188315c40b22c0fa8751365ba453c280001130cfb41380fdd7836985e2c4c488fdc3d1d1bd4390f350f0e1b8a448f47ac1c012bcbdd308beca04006b18928c4418aad2b3650677289b1b45ea5a21095c5310301100ed4d0a8a440b03f1254ce1efb2d82a94cf001cffa0e7fd6ada813a2688b240130a69de998b87aebcd4c556503a45e559a422ecfbdf2f0e6318a8427e41a7b09017676cfe97afff13797f82f8d631bd29edde424854139c64ab8241e2a2331551401da371f0d3294843fd8f645019a04c07607342c70cf4cc793068355eaccdd671601bc79f0119f97113775379bf58f3f5d9d122766909b797947127b28248ff0720501c1eb3aa1717c2a696ce0aba6c5b5bda44c4eda5cf69ae376cc8b334a2c23fb2b0001374feb2041bfd423c6cc3e064ee2b4705748a082836d39dd723515357fb06e300000000000000000000000"
}
"""
} }

View File

@ -57,9 +57,3 @@ class WalletTests: XCTestCase {
// XCTAssertNoThrow( try FileManager.default.removeItem(at: cacheData!) ) // XCTAssertNoThrow( try FileManager.default.removeItem(at: cacheData!) )
} }
} }
enum WalletBirthdayProvider {
static var testBirthday: WalletBirthday {
WalletBirthday()
}
}

View File

@ -125,7 +125,7 @@ class TestCoordinator {
outputParamsURL: try __outputParamsURL(), outputParamsURL: try __outputParamsURL(),
spendingKey: spendingKey, spendingKey: spendingKey,
unifiedViewingKey: unifiedViewingKey, unifiedViewingKey: unifiedViewingKey,
walletBirthday: WalletBirthday.birthday(with: birthday, network: network), walletBirthday: Checkpoint.birthday(with: birthday, network: network),
network: network, network: network,
loggerProxy: SampleLogger(logLevel: .debug) loggerProxy: SampleLogger(logLevel: .debug)
) )
@ -289,7 +289,7 @@ enum TestSynchronizerBuilder {
outputParamsURL: URL, outputParamsURL: URL,
spendingKey: String, spendingKey: String,
unifiedViewingKey: UnifiedViewingKey, unifiedViewingKey: UnifiedViewingKey,
walletBirthday: WalletBirthday, walletBirthday: Checkpoint,
network: ZcashNetwork, network: ZcashNetwork,
loggerProxy: Logger? = nil loggerProxy: Logger? = nil
) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) { ) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) {
@ -361,7 +361,7 @@ enum TestSynchronizerBuilder {
spendParamsURL: URL, spendParamsURL: URL,
outputParamsURL: URL, outputParamsURL: URL,
seedBytes: [UInt8], seedBytes: [UInt8],
walletBirthday: WalletBirthday, walletBirthday: Checkpoint,
network: ZcashNetwork, network: ZcashNetwork,
loggerProxy: Logger? = nil loggerProxy: Logger? = nil
) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) { ) throws -> (spendingKeys: [String]?, synchronizer: SDKSynchronizer) {