[#401] DecodingError when refreshing pending transactions (#402)

Closes #401
This commit changes the way Codable in implemented for Zatoshi and PendingTransaction.

SQLite attempts to decode Custom Types as JSONStrings inside a TEXT column whereas Zatoshi only needs to be an INTEGER that can be treated as an Int64 value

`ConfirmedTransaction` entity is not affected because it is already deserialized
in a custom fashion whereas `PendingTransaction` was relying on `Codable` and
`CodingKey`.
This commit is contained in:
Francisco Gindre 2022-06-27 12:51:13 -03:00 committed by GitHub
parent b9ae012e09
commit c7a27c0b86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 91 additions and 43 deletions

View File

@ -20,15 +20,15 @@ This is an alpha build and is currently under active development. Please be advi
## Swift Package Manager
Add a package with the source "https://github.com/zcash/ZcashLightClientKit.git" and from version `0.13.0` onwards in either Xcode's GUI or in your `Package.swift` file.
Add a package with the source "https://github.com/zcash/ZcashLightClientKit.git" and from version `0.14.0-beta` onwards in either Xcode's GUI or in your `Package.swift` file.
### Beta version support for Xcode projects
If you want to include a beta version of `ZCashLightClientKit` in an Xcode project e.g `0.13.0-beta.2` you will need to specify it with the commit sha instead as it does not appear that Xcode supports 'meta data' from semantic version strings for swift packages (at the time of writing).
If you want to include a beta version of `ZCashLightClientKit` in an Xcode project e.g `0.14.0-beta` you will need to specify it with the commit sha instead as it does not appear that Xcode supports 'meta data' from semantic version strings for swift packages (at the time of writing).
## Cocoapods Support
Add `pod "ZcashLightClientKit", ~> "0.13.0-beta.2"` to the target you want to add the kit too.
Add `pod "ZcashLightClientKit", ~> "0.14.0-beta"` to the target you want to add the kit too.
# Testing

View File

@ -7,8 +7,7 @@
import Foundation
import SQLite
struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
struct PendingTransaction: PendingTransactionEntity, Codable {
enum CodingKeys: String, CodingKey {
case toAddress = "to_address"
case accountIndex = "account_index"
@ -63,6 +62,82 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
)
}
init(
toAddress: String,
accountIndex: Int,
minedHeight: BlockHeight,
expiryHeight: BlockHeight,
cancelled: Int,
encodeAttempts: Int,
submitAttempts: Int,
errorMessage: String?,
errorCode: Int?,
createTime: TimeInterval,
raw: Data?,
id: Int?,
value: Zatoshi,
memo: Data?,
rawTransactionId: Data?
) {
self.toAddress = toAddress
self.accountIndex = accountIndex
self.minedHeight = minedHeight
self.expiryHeight = expiryHeight
self.cancelled = cancelled
self.encodeAttempts = encodeAttempts
self.submitAttempts = submitAttempts
self.errorMessage = errorMessage
self.errorCode = errorCode
self.createTime = createTime
self.raw = raw
self.id = id
self.value = value
self.memo = memo
self.rawTransactionId = rawTransactionId
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.toAddress = try container.decode(String.self, forKey: .toAddress)
self.accountIndex = try container.decode(Int.self, forKey: .accountIndex)
self.minedHeight = try container.decode(BlockHeight.self, forKey: .minedHeight)
self.expiryHeight = try container.decode(BlockHeight.self, forKey: .expiryHeight)
self.cancelled = try container.decode(Int.self, forKey: .cancelled)
self.encodeAttempts = try container.decode(Int.self, forKey: .encodeAttempts)
self.submitAttempts = try container.decode(Int.self, forKey: .submitAttempts)
self.errorMessage = try container.decodeIfPresent(String.self, forKey: .errorMessage)
self.errorCode = try container.decodeIfPresent(Int.self, forKey: .errorCode)
self.createTime = try container.decode(TimeInterval.self, forKey: .createTime)
self.raw = try container.decodeIfPresent(Data.self, forKey: .raw)
self.id = try container.decodeIfPresent(Int.self, forKey: .id)
let zatoshiValue = try container.decode(Int64.self, forKey: .value)
self.value = Zatoshi(zatoshiValue)
self.memo = try container.decodeIfPresent(Data.self, forKey: .memo)
self.rawTransactionId = try container.decodeIfPresent(Data.self, forKey: .rawTransactionId)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.toAddress, forKey: .toAddress)
try container.encode(self.accountIndex, forKey: .accountIndex)
try container.encode(self.minedHeight, forKey: .minedHeight)
try container.encode(self.expiryHeight, forKey: .expiryHeight)
try container.encode(self.cancelled, forKey: .cancelled)
try container.encode(self.encodeAttempts, forKey: .encodeAttempts)
try container.encode(self.submitAttempts, forKey: .submitAttempts)
try container.encodeIfPresent(self.errorMessage, forKey: .errorMessage)
try container.encodeIfPresent(self.errorCode, forKey: .errorCode)
try container.encode(self.createTime, forKey: .createTime)
try container.encodeIfPresent(self.raw, forKey: .raw)
try container.encodeIfPresent(self.id, forKey: .id)
try container.encode(self.value.amount, forKey: .value)
try container.encodeIfPresent(self.memo, forKey: .memo)
try container.encodeIfPresent(self.rawTransactionId, forKey: .rawTransactionId)
}
func isSameTransactionId<T>(other: T) -> Bool where T: RawIdentifiable {
self.rawTransactionId == other.rawTransactionId
}

View File

@ -1,38 +0,0 @@
//
// Zatoshi+Codable.swift
//
//
// Created by Francisco Gindre on 6/20/22.
//
import Foundation
/// This extension is needed to support SQLite Swift Codable Types
extension Zatoshi: Codable {
enum CodingError: Error {
case encodingError(String)
}
/// This codable implementation responds to limitaitons that SQLite Swift explains
/// on its documentation https://github.com/stephencelis/SQLite.swift/blob/master/Documentation/Index.md#codable-types
/// SQLite Sqift will encode custom types into a string and stores it in a single column. They do so by
/// leveraging the Codable interface so this has to abide by them and their choice.
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let value = try container.decode(String.self)
guard let amount = Int64(value) else {
throw CodingError.encodingError("Decoding Error")
}
self.amount = amount
}
/// This codable implementation responds to limitaitons that SQLite Swift explains
/// on its documentation https://github.com/stephencelis/SQLite.swift/blob/master/Documentation/Index.md#codable-types
/// SQLite Sqift will encode custom types into a string and stores it in a single column. They do so by
/// leveraging the Codable interface so this has to abide by them and their choice.
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(String(self.amount))
}
}

View File

@ -105,4 +105,15 @@ public protocol UnifiedAddress {
public struct WalletBalance {
public var verified: Zatoshi
public var total: Zatoshi
public init(verified: Zatoshi, total: Zatoshi) {
self.verified = verified
self.total = total
}
}
public extension WalletBalance {
static var zero: WalletBalance {
Self(verified: .zero, total: .zero)
}
}