forked from EOSIO/eosio-swift
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEosioAbieosSerializationProvider.swift
247 lines (206 loc) · 10.1 KB
/
EosioAbieosSerializationProvider.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
//
// EosioAbieosSerializationProvider.swift
// EosioAbieosSerializationProvider
//
// Created by Todd Bowden on 6/16/18.
// Copyright (c) 2017-2019 block.one and its contributors. All rights reserved.
//
import Foundation
import EosioSwift
#if SWIFT_PACKAGE
import Abieos
#endif
/// Serialization provider implementation for EOSIO SDK for Swift using ABIEOS.
/// Responsible for ABI-driven transaction and action serialization and deserialization
/// between JSON and binary data representations.
public class EosioAbieosSerializationProvider: EosioSerializationProviderProtocol {
/// Used to hold errors.
public class Error: EosioError { }
private var context = abieos_create()
private var abiJsonString = ""
/// Getter to return error as a String.
public var error: String? {
return String(validatingUTF8: abieos_get_error(context))
}
/// Default init.
required public init() {
}
deinit {
abieos_destroy(context)
}
/// Convert ABIEOS String data to UInt64 value.
///
/// - Parameter string: String data to convert.
/// - Returns: A UInt64 value.
public func name64(string: String?) -> UInt64 {
guard let string = string else { return 0 }
return abieos_string_to_name(context, string)
}
/// Convert ABIEOS UInt64 data to String value.
///
/// - Parameter name64: A UInt64 value to convert.
/// - Returns: A string value.
public func string(name64: UInt64) -> String? {
return String(validatingUTF8: abieos_name_to_string(context, name64))
}
private func refreshContext() {
if context != nil {
abieos_destroy(context)
}
context = abieos_create()
}
private func getAbiJsonFile(fileName: String) throws -> String {
var abiString = ""
#if MAIN_BUNDLE
let path = Bundle.main.url(forResource: fileName, withExtension: nil)?.path ?? ""
#elseif COCOAPODS
let path = Bundle(for: EosioAbieosSerializationProvider.self).url(forResource: fileName, withExtension: nil)?.path ?? ""
#else
let path = Bundle.module.url(forResource: fileName, withExtension: nil)?.path ?? ""
#endif
abiString = try NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String
guard abiString != "" else {
throw Error(.serializationProviderError, reason: "Json to hex -- No ABI file found for \(fileName)")
}
return abiString
}
/// Convert JSON Transaction data representation to ABIEOS binary representation of Transaction data.
///
/// - Parameter json: The JSON representation of Transaction data to serialize.
/// - Returns: A binary String of Transaction data.
/// - Throws: If the data cannot be serialized for any reason.
public func serializeTransaction(json: String) throws -> String {
let transactionJson = try getAbiJsonFile(fileName: "transaction.abi.json")
return try serialize(contract: nil, name: "", type: "transaction", json: json, abi: transactionJson)
}
/// Convert JSON ABI data representation to ABIEOS binary of data.
///
/// - Parameter json: The JSON data String to serialize.
/// - Returns: A String of binary data.
/// - Throws: If the data cannot be serialized for any reason.
public func serializeAbi(json: String) throws -> String {
refreshContext()
let jsonToBinResult = abieos_abi_json_to_bin(context, json)
guard jsonToBinResult == 1 else {
throw Error(.serializationProviderError, reason: "serializeAbi - unable to convert to binary. \(self.error ?? "")")
}
guard let hex = String(validatingUTF8: abieos_get_bin_hex(context)) else {
throw Error(.serializationProviderError, reason: "serializeUnable to convert binary to hex")
}
return hex
}
/// Calls ABIEOS to carry out JSON to binary conversion using ABIs.
///
/// - Parameters:
/// - contract: An optional String representing contract name for the serialize action lookup for this ABIEOS conversion.
/// - name: An optional String representing an action name that is used in conjunction with contract (above) to derive the serialize type name.
/// - type: An optional string representing the type name for the serialize action lookup for this serialize conversion.
/// - json: The JSON data String to serialize to binary.
/// - abi: A String representation of the ABI to use for conversion.
/// - Returns: A String of binary serialized data.
/// - Throws: If the data cannot be serialized for any reason.
public func serialize(contract: String?, name: String = "", type: String? = nil, json: String, abi: String) throws -> String {
refreshContext()
let contract64 = name64(string: contract)
abiJsonString = abi
// set the abi
let setAbiResult = abieos_set_abi(context, contract64, abiJsonString)
guard setAbiResult == 1 else {
throw Error(.serializationProviderError, reason: "Json to hex -- Unable to set ABI. \(self.error ?? "")")
}
// get the type name for the action
guard let type = type ?? getType(action: name, contract: contract64) else {
throw Error(.serializationProviderError, reason: "Unable find type for action \(name). \(self.error ?? "")")
}
var jsonToBinResult: Int32 = 0
jsonToBinResult = abieos_json_to_bin_reorderable(context, contract64, type, json)
guard jsonToBinResult == 1 else {
throw Error(.serializationProviderError, reason: "Unable to pack json to bin. \(self.error ?? "")")
}
guard let hex = String(validatingUTF8: abieos_get_bin_hex(context)) else {
throw Error(.serializationProviderError, reason: "Unable to convert binary to hex")
}
return hex
}
/// Converts a binary string of ABIEOS Transaction data to JSON string representation of Transaction data.
///
/// - Parameter hex: The binary Transaction data String to deserialize.
/// - Returns: A String of JSON Transaction data.
/// - Throws: If the data cannot be deserialized for any reason.
public func deserializeTransaction(hex: String) throws -> String {
let transactionJson = try getAbiJsonFile(fileName: "transaction.abi.json")
return try deserialize(contract: nil, name: "", type: "transaction", hex: hex, abi: transactionJson)
}
/// Converts a binary string of ABIEOS data to JSON string data.
///
/// - Parameter hex: The binary data String to deserialize.
/// - Returns: A String of JSON data.
/// - Throws: If the data cannot be deserialized for any reason.
public func deserializeAbi(hex: String) throws -> String {
refreshContext()
let abiData = try Data(hex: hex)
var jsonString: String? = nil
try abiData.withUnsafeBytes { rawAbiPointer in
let abiPointer = rawAbiPointer.bindMemory(to: Int8.self)
guard let abiBytes = abiPointer.baseAddress else {
throw Error(.serializationProviderError, reason: "Base address of abi buffer is nil.")
}
if let jsonCstring = abieos_abi_bin_to_json(context, abiBytes, abiData.count) {
jsonString = String(cString: jsonCstring)
}
}
guard let returnString = jsonString else {
throw Error(.serializationProviderError, reason: "Unable to convert hex json. \(self.error ?? "")")
}
return returnString
}
/// Calls ABIEOS to carry out binary to JSON conversion using ABIs.
///
/// - Parameters:
/// - contract: An optional String representing contract name for the ABIEOS action lookup for this ABIEOS conversion.
/// - name: An optional String representing an action name that is used in conjunction with contract (above) to derive the ABIEOS type name.
/// - type: An optional string representing the type name for the ABIEOS action lookup for this ABIEOS conversion.
/// - hex: The binary data String to deserialize to a JSON String.
/// - abi: A String representation of the ABI to use for conversion.
/// - Returns: A String of JSON data.
/// - Throws: If the data cannot be deserialized for any reason.
public func deserialize(contract: String?, name: String = "", type: String? = nil, hex: String, abi: String) throws -> String {
refreshContext()
let contract64 = name64(string: contract)
abiJsonString = abi
// set the abi
let setAbiResult = abieos_set_abi(context, contract64, abiJsonString)
guard setAbiResult == 1 else {
throw Error(.serializationProviderError, reason: "Hex to json -- Unable to set ABI. \(self.error ?? "")")
}
// get the type name for the action
guard let type = type ?? getType(action: name, contract: contract64) else {
throw Error(.serializationProviderError, reason: "Unable find type for action \(name). \(self.error ?? "")")
}
if let json = abieos_hex_to_json(context, contract64, type, hex) {
if let string = String(validatingUTF8: json) {
return string
} else {
throw Error(.serializationProviderError, reason: "Unable to convert c string json to String.)")
}
} else {
throw Error(.serializationProviderError, reason: "Unable to unpack hex to json. \(self.error ?? "")")
}
}
// Get the type name for the action and contract.
private func getType(action: String, contract: UInt64) -> String? {
let action64 = name64(string: action)
if let type = abieos_get_type_for_action(context, contract, action64) {
return String(validatingUTF8: type)
} else {
return nil
}
}
private func jsonString(dictionary: [String: Any]) -> String? {
if let data = try? JSONSerialization.data(withJSONObject: dictionary, options: []) {
return String(data: data, encoding: .utf8)
} else {
return nil
}
}
}