Issue 208 - Improve API method to request transaction history
This commit is contained in:
parent
0df4b9e4f2
commit
972fb08926
|
@ -65,9 +65,7 @@ class TransactionsDataSource: NSObject, UITableViewDataSource {
|
||||||
}
|
}
|
||||||
case .all:
|
case .all:
|
||||||
transactions = (synchronizer.pendingTransactions.map { $0.transactionEntity } +
|
transactions = (synchronizer.pendingTransactions.map { $0.transactionEntity } +
|
||||||
synchronizer.clearedTransactions.map { $0.transactionEntity } +
|
synchronizer.clearedTransactions.map { $0.transactionEntity }).map { TransactionDetailModel(transaction: $0)}
|
||||||
synchronizer.receivedTransactions.map { $0.transactionEntity } +
|
|
||||||
synchronizer.sentTransactions.map { $0.transactionEntity }).map { TransactionDetailModel(transaction: $0)}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -202,6 +202,55 @@ class TransactionSQLDAO: TransactionRepository {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func findAll(from transaction: ConfirmedTransactionEntity?, limit: Int) throws -> [ConfirmedTransactionEntity]? {
|
||||||
|
guard let fromTransaction = transaction else {
|
||||||
|
return try findAll(offset: 0, limit: limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
return try dbProvider.connection().run("""
|
||||||
|
SELECT transactions.id_tx AS id,
|
||||||
|
transactions.block AS minedHeight,
|
||||||
|
transactions.tx_index AS transactionIndex,
|
||||||
|
transactions.txid AS rawTransactionId,
|
||||||
|
transactions.expiry_height AS expiryHeight,
|
||||||
|
transactions.raw AS raw,
|
||||||
|
sent_notes.address AS toAddress,
|
||||||
|
CASE
|
||||||
|
WHEN sent_notes.value IS NOT NULL THEN sent_notes.value
|
||||||
|
ELSE received_notes.value
|
||||||
|
end AS value,
|
||||||
|
CASE
|
||||||
|
WHEN sent_notes.memo IS NOT NULL THEN sent_notes.memo
|
||||||
|
ELSE received_notes.memo
|
||||||
|
end AS memo,
|
||||||
|
CASE
|
||||||
|
WHEN sent_notes.id_note IS NOT NULL THEN sent_notes.id_note
|
||||||
|
ELSE received_notes.id_note
|
||||||
|
end AS noteId,
|
||||||
|
blocks.time AS blockTimeInSeconds
|
||||||
|
FROM transactions
|
||||||
|
LEFT JOIN received_notes
|
||||||
|
ON transactions.id_tx = received_notes.tx
|
||||||
|
LEFT JOIN sent_notes
|
||||||
|
ON transactions.id_tx = sent_notes.tx
|
||||||
|
LEFT JOIN blocks
|
||||||
|
ON transactions.block = blocks.height
|
||||||
|
WHERE (\(fromTransaction.blockTimeInSeconds), \(fromTransaction.transactionIndex)) > (blocktimeinseconds, transactionIndex) AND
|
||||||
|
(sent_notes.address IS NULL AND received_notes.is_change != 1)
|
||||||
|
OR sent_notes.address IS NOT NULL
|
||||||
|
ORDER BY ( minedheight IS NOT NULL ),
|
||||||
|
minedheight DESC,
|
||||||
|
blocktimeinseconds DESC,
|
||||||
|
id DESC
|
||||||
|
LIMIT \(limit)
|
||||||
|
""").compactMap({ (bindings) -> ConfirmedTransactionEntity? in
|
||||||
|
guard let tx = TransactionBuilder.createConfirmedTransaction(from: bindings) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return tx
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func findTransactions(in range: BlockRange, limit: Int = Int.max) throws -> [TransactionEntity]? {
|
func findTransactions(in range: BlockRange, limit: Int = Int.max) throws -> [TransactionEntity]? {
|
||||||
try dbProvider.connection().run("""
|
try dbProvider.connection().run("""
|
||||||
SELECT transactions.id_tx AS id,
|
SELECT transactions.id_tx AS id,
|
||||||
|
|
|
@ -135,4 +135,6 @@ public extension ConfirmedTransactionEntity {
|
||||||
var blockTimeInMilliseconds: Double {
|
var blockTimeInMilliseconds: Double {
|
||||||
self.blockTimeInSeconds * 1000
|
self.blockTimeInSeconds * 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,6 @@ public class Initializer {
|
||||||
transactionRepository: transactionRepository,
|
transactionRepository: transactionRepository,
|
||||||
backend: rustBackend)
|
backend: rustBackend)
|
||||||
|
|
||||||
|
|
||||||
guard try rustBackend.initAccountsTable(dbData: dataDbURL, exfvks: viewingKeys) else {
|
guard try rustBackend.initAccountsTable(dbData: dataDbURL, exfvks: viewingKeys) else {
|
||||||
throw rustBackend.lastError() ?? InitializerError.accountInitFailed
|
throw rustBackend.lastError() ?? InitializerError.accountInitFailed
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ protocol TransactionRepository {
|
||||||
func findAllSentTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]?
|
func findAllSentTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]?
|
||||||
func findAllReceivedTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]?
|
func findAllReceivedTransactions(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]?
|
||||||
func findAll(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]?
|
func findAll(offset: Int, limit: Int) throws -> [ConfirmedTransactionEntity]?
|
||||||
|
func findAll(from: ConfirmedTransactionEntity?, limit: Int) throws -> [ConfirmedTransactionEntity]?
|
||||||
func lastScannedHeight() throws -> BlockHeight
|
func lastScannedHeight() throws -> BlockHeight
|
||||||
func isInitialized() throws -> Bool
|
func isInitialized() throws -> Bool
|
||||||
func findEncodedTransactionBy(txId: Int) -> EncodedTransaction?
|
func findEncodedTransactionBy(txId: Int) -> EncodedTransaction?
|
||||||
|
|
|
@ -92,7 +92,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
|
|
||||||
static func initAccountsTable(dbData: URL, exfvks: [String]) throws -> Bool {
|
static func initAccountsTable(dbData: URL, exfvks: [String]) throws -> Bool {
|
||||||
let dbData = dbData.osStr()
|
let dbData = dbData.osStr()
|
||||||
let viewingKeys = exfvks.map { UnsafePointer(strdup($0)) }
|
let viewingKeys = exfvks.map { UnsafePointer(strdup($0)) }
|
||||||
|
|
||||||
guard exfvks.count > 0 else {
|
guard exfvks.count > 0 else {
|
||||||
throw RustWeldingError.malformedStringInput
|
throw RustWeldingError.malformedStringInput
|
||||||
|
@ -100,7 +100,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
|
|
||||||
let res = zcashlc_init_accounts_table_with_keys(dbData.0, dbData.1, viewingKeys, UInt(viewingKeys.count));
|
let res = zcashlc_init_accounts_table_with_keys(dbData.0, dbData.1, viewingKeys, UInt(viewingKeys.count));
|
||||||
|
|
||||||
viewingKeys.compactMap({UnsafeMutablePointer(mutating: $0)}).forEach({ free($0) })
|
viewingKeys.compactMap({ UnsafeMutablePointer(mutating: $0) }).forEach({ free($0) })
|
||||||
|
|
||||||
guard res else {
|
guard res else {
|
||||||
if let error = lastError() {
|
if let error = lastError() {
|
||||||
|
|
|
@ -57,7 +57,6 @@ public protocol ZcashRustBackendWelding {
|
||||||
*/
|
*/
|
||||||
static func initAccountsTable(dbData: URL, seed: [UInt8], accounts: Int32) -> [String]?
|
static func initAccountsTable(dbData: URL, seed: [UInt8], accounts: Int32) -> [String]?
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
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
|
||||||
- Parameters:
|
- Parameters:
|
||||||
|
|
|
@ -105,6 +105,16 @@ public protocol Synchronizer {
|
||||||
*/
|
*/
|
||||||
func paginatedTransactions(of kind: TransactionKind) -> PaginatedTransactionRepository
|
func paginatedTransactions(of kind: TransactionKind) -> PaginatedTransactionRepository
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a list of confirmed transactions that preceed the given transaction with a limit count.
|
||||||
|
- Parameters:
|
||||||
|
- from: the confirmed transaction from which the query should start from or nil to retrieve from the most recent transaction
|
||||||
|
- limit: the maximum amount of items this should return if available
|
||||||
|
- Returns: an array with the given Transactions or nil
|
||||||
|
|
||||||
|
*/
|
||||||
|
func allConfirmedTransactions(from transaction: ConfirmedTransactionEntity?, limit: Int) throws -> [ConfirmedTransactionEntity]?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
gets the latest downloaded height from the compact block cache
|
gets the latest downloaded height from the compact block cache
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -63,7 +63,7 @@ public extension Notification.Name {
|
||||||
Synchronizer implementation for UIKit and iOS 12+
|
Synchronizer implementation for UIKit and iOS 12+
|
||||||
*/
|
*/
|
||||||
public class SDKSynchronizer: Synchronizer {
|
public class SDKSynchronizer: Synchronizer {
|
||||||
|
|
||||||
public struct NotificationKeys {
|
public struct NotificationKeys {
|
||||||
public static let progress = "SDKSynchronizer.progress"
|
public static let progress = "SDKSynchronizer.progress"
|
||||||
public static let blockHeight = "SDKSynchronizer.blockHeight"
|
public static let blockHeight = "SDKSynchronizer.blockHeight"
|
||||||
|
@ -467,6 +467,10 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
try transactionRepository.findAllSentTransactions(offset: 0, limit: Int.max) ?? [ConfirmedTransactionEntity]()
|
try transactionRepository.findAllSentTransactions(offset: 0, limit: Int.max) ?? [ConfirmedTransactionEntity]()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func allConfirmedTransactions(from transaction: ConfirmedTransactionEntity?, limit: Int) throws -> [ConfirmedTransactionEntity]? {
|
||||||
|
try transactionRepository.findAll(from: transaction, limit: limit)
|
||||||
|
}
|
||||||
|
|
||||||
public func paginatedTransactions(of kind: TransactionKind = .all) -> PaginatedTransactionRepository {
|
public func paginatedTransactions(of kind: TransactionKind = .all) -> PaginatedTransactionRepository {
|
||||||
PagedTransactionRepositoryBuilder.build(initializer: initializer, kind: .all)
|
PagedTransactionRepositoryBuilder.build(initializer: initializer, kind: .all)
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,6 +109,66 @@ class TransactionRepositoryTests: XCTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testFindAllFrom() throws {
|
||||||
|
guard let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max),
|
||||||
|
let allFromNil = try self.transactionRepository.findAll(from: nil, limit: Int.max)
|
||||||
|
else {
|
||||||
|
return XCTFail("find all failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
XCTAssertEqual(transactions.count, allFromNil.count)
|
||||||
|
|
||||||
|
for t in transactions {
|
||||||
|
guard allFromNil.first(where: { $0.rawTransactionId == t.rawTransactionId}) != nil else {
|
||||||
|
XCTFail("not equal")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFindAllFromSlice() throws {
|
||||||
|
|
||||||
|
let limit = 4
|
||||||
|
let start = 7
|
||||||
|
guard let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max),
|
||||||
|
let allFromNil = try self.transactionRepository.findAll(from: transactions[start], limit: limit)
|
||||||
|
else {
|
||||||
|
return XCTFail("find all failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
XCTAssertEqual(limit, allFromNil.count)
|
||||||
|
|
||||||
|
let slice = transactions[start + 1 ... start + limit]
|
||||||
|
XCTAssertEqual(slice.count, allFromNil.count)
|
||||||
|
for t in slice {
|
||||||
|
guard allFromNil.first(where: { $0.rawTransactionId == t.rawTransactionId}) != nil else {
|
||||||
|
XCTFail("not equal")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func testFindAllFromLastSlice() throws {
|
||||||
|
|
||||||
|
let limit = 10
|
||||||
|
let start = 20
|
||||||
|
guard let transactions = try self.transactionRepository.findAll(offset: 0, limit: Int.max),
|
||||||
|
let allFromNil = try self.transactionRepository.findAll(from: transactions[start], limit: limit)
|
||||||
|
else {
|
||||||
|
return XCTFail("find all failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
let slice = transactions[start + 1 ..< transactions.count]
|
||||||
|
XCTAssertEqual(slice.count, allFromNil.count)
|
||||||
|
for t in slice {
|
||||||
|
guard allFromNil.first(where: { $0.rawTransactionId == t.rawTransactionId}) != nil else {
|
||||||
|
XCTFail("not equal")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Data {
|
extension Data {
|
||||||
|
|
|
@ -10,6 +10,10 @@ import Foundation
|
||||||
@testable import ZcashLightClientKit
|
@testable import ZcashLightClientKit
|
||||||
|
|
||||||
class MockTransactionRepository: TransactionRepository {
|
class MockTransactionRepository: TransactionRepository {
|
||||||
|
func findAll(from: ConfirmedTransactionEntity?, limit: Int) throws -> [ConfirmedTransactionEntity]? {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
func findTransactions(in range: BlockRange, limit: Int) throws -> [TransactionEntity]? {
|
func findTransactions(in range: BlockRange, limit: Int) throws -> [TransactionEntity]? {
|
||||||
nil
|
nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue