From f944d8e6c1a32518fa2cc9d72e159fb1098d7ead Mon Sep 17 00:00:00 2001 From: Joel Carter Date: Tue, 26 Nov 2024 07:09:54 -0600 Subject: [PATCH 1/4] Add signatures to BW meta --- Sources/XyoClient/BoundWitness/BoundWitness.swift | 9 ++++++--- Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift | 2 +- Sources/XyoClient/BoundWitness/BoundWitnessJson.swift | 9 ++++++--- .../XyoClient/BoundWitness/Meta/BoundWitnessMeta.swift | 4 +--- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Sources/XyoClient/BoundWitness/BoundWitness.swift b/Sources/XyoClient/BoundWitness/BoundWitness.swift index 2616cb4..d91db6b 100644 --- a/Sources/XyoClient/BoundWitness/BoundWitness.swift +++ b/Sources/XyoClient/BoundWitness/BoundWitness.swift @@ -10,7 +10,7 @@ public class BoundWitness: Payload, BoundWitnessBody, BoundWitnessMeta, public var _hash: String? = nil - public var _signatures: [String]? = nil + public var signatures: [String]? = nil public var addresses: [String] = [] @@ -29,8 +29,8 @@ public class BoundWitness: Payload, BoundWitnessBody, BoundWitnessMeta, enum CodingKeys: String, CodingKey { case _client case _hash - case _signatures case addresses + case meta = "$meta" case payload_hashes case payload_schemas case previous_hashes @@ -51,7 +51,10 @@ public class BoundWitness: Payload, BoundWitnessBody, BoundWitnessMeta, func encodeMetaFields(_ container: inout KeyedEncodingContainer) throws { try container.encodeIfPresent(_client, forKey: ._client) try container.encodeIfPresent(_hash, forKey: ._hash) - try container.encodeIfPresent(_signatures, forKey: ._signatures) + let meta = [ + "signatures": signatures + ] + try container.encode(meta, forKey: .meta) } func encodeBodyFields(_ container: inout KeyedEncodingContainer) throws { diff --git a/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift b/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift index f9690a5..50b0897 100644 --- a/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift +++ b/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift @@ -71,7 +71,7 @@ public class BoundWitnessBuilder { let bw = BoundWitness() let hashable = hashableFields() let hash = try BoundWitnessBuilder.hash(hashable) - bw._signatures = try self.sign(hash: hash) + bw.signatures = try self.sign(hash: hash) bw._hash = hash bw._client = "swift" bw.addresses = _accounts.map { witness in witness.address } diff --git a/Sources/XyoClient/BoundWitness/BoundWitnessJson.swift b/Sources/XyoClient/BoundWitness/BoundWitnessJson.swift index f214901..ea38175 100644 --- a/Sources/XyoClient/BoundWitness/BoundWitnessJson.swift +++ b/Sources/XyoClient/BoundWitness/BoundWitnessJson.swift @@ -4,8 +4,8 @@ public class XyoBoundWitnessJson: BoundWitnessBodyJson, BoundWitnessMeta { enum CodingKeys: String, CodingKey { case _client case _hash - case _signatures case addresses + case meta = "$meta" case payload_hashes case payload_schemas case previous_hashes @@ -15,13 +15,16 @@ public class XyoBoundWitnessJson: BoundWitnessBodyJson, BoundWitnessMeta { public var _client: String? public var _hash: String? - public var _signatures: [String]? + public var signatures: [String]? public var _query: String? func encodeMetaFields(_ container: inout KeyedEncodingContainer) throws { try container.encode(_client, forKey: ._client) try container.encode(_hash, forKey: ._hash) - try container.encode(_signatures, forKey: ._signatures) + let meta = [ + "signatures": signatures + ] + try container.encode(meta, forKey: .meta) } func encodeBodyFields(_ container: inout KeyedEncodingContainer) throws { diff --git a/Sources/XyoClient/BoundWitness/Meta/BoundWitnessMeta.swift b/Sources/XyoClient/BoundWitness/Meta/BoundWitnessMeta.swift index 46a20a0..20f63c6 100644 --- a/Sources/XyoClient/BoundWitness/Meta/BoundWitnessMeta.swift +++ b/Sources/XyoClient/BoundWitness/Meta/BoundWitnessMeta.swift @@ -1,7 +1,5 @@ import Foundation public protocol BoundWitnessMeta { - var _client: String? { get set } - var _hash: String? { get set } - var _signatures: [String]? { get set } + var signatures: [String]? { get set } } From b21039ae68fa3848686ce9392e2b304c2b91729e Mon Sep 17 00:00:00 2001 From: Joel Carter Date: Tue, 26 Nov 2024 07:26:23 -0600 Subject: [PATCH 2/4] Filtering of $meta from data hashable fields --- .../BoundWitness/BoundWitnessBuilder.swift | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift b/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift index 50b0897..8b37236 100644 --- a/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift +++ b/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift @@ -84,19 +84,26 @@ public class BoundWitnessBuilder { return (bw, _payloads) } - private static func filterUnderscoreKeys(_ jsonObject: Any) -> Any { + private static func isMetaField(_ key: String) -> Bool { + // Remove keys starting with "_" + return key.hasPrefix("_") || + // Remove keys starting with "$" + key.hasPrefix("$") + } + + private static func dataHashableFields(_ jsonObject: Any) -> Any { if let dictionary = jsonObject as? [String: Any] { // Process dictionaries: filter keys, sort, and recurse let filteredDictionary = dictionary - .filter { !$0.key.hasPrefix("_") } // Remove keys starting with "_" + .filter { !isMetaField($0.key) } // Filter meta fields .sorted { $0.key < $1.key } // Sort keys lexicographically .reduce(into: [String: Any]()) { result, pair in - result[pair.key] = filterUnderscoreKeys(pair.value) // Recurse on values + result[pair.key] = dataHashableFields(pair.value) // Recurse on values } return filteredDictionary } else if let array = jsonObject as? [Any] { // Process arrays: recursively process each element - return array.map { filterUnderscoreKeys($0) } + return array.map { dataHashableFields($0) } } else { // Return primitives (String, Number, etc.) return jsonObject @@ -132,8 +139,8 @@ public class BoundWitnessBuilder { throw BoundWitnessBuilderError.encodingError } - // Recursively filter keys starting with "_" - let filteredJSON = filterUnderscoreKeys(jsonObject) + // Recursively filter keys that are data hashable + let filteredJSON = dataHashableFields(jsonObject) // Encode the filtered JSON back to data let filteredData = try JSONSerialization.data( From 7618194a45a82c93dfef8baa5f5941fe0dd2d320 Mon Sep 17 00:00:00 2001 From: Joel Carter Date: Tue, 26 Nov 2024 07:28:59 -0600 Subject: [PATCH 3/4] Invert boolean for readability --- .../XyoClient/BoundWitness/BoundWitnessBuilder.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift b/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift index 8b37236..2513d35 100644 --- a/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift +++ b/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift @@ -83,19 +83,19 @@ public class BoundWitnessBuilder { } return (bw, _payloads) } - - private static func isMetaField(_ key: String) -> Bool { + + private static func isDataField(_ key: String) -> Bool { // Remove keys starting with "_" - return key.hasPrefix("_") || + return !key.hasPrefix("_") && // Remove keys starting with "$" - key.hasPrefix("$") + !key.hasPrefix("$") } private static func dataHashableFields(_ jsonObject: Any) -> Any { if let dictionary = jsonObject as? [String: Any] { // Process dictionaries: filter keys, sort, and recurse let filteredDictionary = dictionary - .filter { !isMetaField($0.key) } // Filter meta fields + .filter { isDataField($0.key) } // Filter meta fields .sorted { $0.key < $1.key } // Sort keys lexicographically .reduce(into: [String: Any]()) { result, pair in result[pair.key] = dataHashableFields(pair.value) // Recurse on values From e8de3ee62d34804287dfb1d74e995b9048ec5b55 Mon Sep 17 00:00:00 2001 From: Joel Carter Date: Tue, 26 Nov 2024 07:29:23 -0600 Subject: [PATCH 4/4] Formatting --- .../BoundWitness/BoundWitnessBuilder.swift | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift b/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift index 2513d35..aca46d9 100644 --- a/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift +++ b/Sources/XyoClient/BoundWitness/BoundWitnessBuilder.swift @@ -86,19 +86,20 @@ public class BoundWitnessBuilder { private static func isDataField(_ key: String) -> Bool { // Remove keys starting with "_" - return !key.hasPrefix("_") && + return !key.hasPrefix("_") // Remove keys starting with "$" - !key.hasPrefix("$") + && !key.hasPrefix("$") } - + private static func dataHashableFields(_ jsonObject: Any) -> Any { if let dictionary = jsonObject as? [String: Any] { // Process dictionaries: filter keys, sort, and recurse - let filteredDictionary = dictionary - .filter { isDataField($0.key) } // Filter meta fields - .sorted { $0.key < $1.key } // Sort keys lexicographically + let filteredDictionary = + dictionary + .filter { isDataField($0.key) } // Filter meta fields + .sorted { $0.key < $1.key } // Sort keys lexicographically .reduce(into: [String: Any]()) { result, pair in - result[pair.key] = dataHashableFields(pair.value) // Recurse on values + result[pair.key] = dataHashableFields(pair.value) // Recurse on values } return filteredDictionary } else if let array = jsonObject as? [Any] { @@ -122,12 +123,12 @@ public class BoundWitnessBuilder { return data.sha256().toHex() } } - + // NOTE: Temporary fix until we have a custom JSON Serializer // this method currently has issues with round tripping of floating // point numbers as precision doesn't round trip static private func hashWithoutUnderscores(_ json: T) throws -> String { - + let encoder = JSONEncoder() encoder.outputFormatting = .sortedKeys @@ -135,7 +136,10 @@ public class BoundWitnessBuilder { let data = try encoder.encode(json) // Decode the JSON into a dictionary, array, or primitive - guard let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { + guard + let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) + as? [String: Any] + else { throw BoundWitnessBuilderError.encodingError }