]>
Commit | Line | Data |
---|---|---|
a88b514e | 1 | /******************************************************************** |
2 | * (C) 2020 Michael Toutonghi | |
3 | * | |
4 | * Distributed under the MIT software license, see the accompanying | |
5 | * file COPYING or http://www.opensource.org/licenses/mit-license.php. | |
6 | * | |
7 | * Support for the Verus Data Exchange Format (VDXF) | |
8 | * | |
9 | */ | |
10 | ||
11 | #include "vdxf.h" | |
7c8e5e18 | 12 | #include "crosschainrpc.h" |
a88b514e | 13 | |
c8c684e9 | 14 | std::string CVDXF::DATA_KEY_SEPARATOR = "::"; |
15 | std::map<uint160,std::pair<std::pair<uint32_t, uint32_t>,std::pair<uint32_t, uint32_t>>> CVDXF::VDXF_TYPES; | |
16 | uint160 CVDXF::STRUCTURED_DATA_KEY = CVDXF_StructuredData::StructuredDataKey(); | |
17 | uint160 CVDXF::ZMEMO_MESSAGE_KEY = CVDXF_Data::ZMemoMessageKey(); | |
18 | uint160 CVDXF::ZMEMO_SIGNATURE_KEY = CVDXF_Data::ZMemoSignatureKey(); | |
a88b514e | 19 | |
20 | std::string TrimLeading(const std::string &Name, unsigned char ch) | |
21 | { | |
22 | std::string nameCopy = Name; | |
23 | int removeSpaces; | |
24 | for (removeSpaces = 0; removeSpaces < nameCopy.size(); removeSpaces++) | |
25 | { | |
26 | if (nameCopy[removeSpaces] != ch) | |
27 | { | |
28 | break; | |
29 | } | |
30 | } | |
31 | if (removeSpaces) | |
32 | { | |
33 | nameCopy.erase(nameCopy.begin(), nameCopy.begin() + removeSpaces); | |
34 | } | |
35 | return nameCopy; | |
36 | } | |
37 | ||
38 | std::string TrimTrailing(const std::string &Name, unsigned char ch) | |
39 | { | |
40 | std::string nameCopy = Name; | |
41 | int removeSpaces; | |
42 | for (removeSpaces = nameCopy.size() - 1; removeSpaces >= 0; removeSpaces--) | |
43 | { | |
44 | if (nameCopy[removeSpaces] != ch) | |
45 | { | |
46 | break; | |
47 | } | |
48 | } | |
49 | nameCopy.resize(nameCopy.size() - ((nameCopy.size() - 1) - removeSpaces)); | |
50 | return nameCopy; | |
51 | } | |
52 | ||
53 | std::string TrimSpaces(const std::string &Name) | |
54 | { | |
55 | return TrimTrailing(TrimLeading(Name, ' '), ' '); | |
56 | } | |
57 | ||
58 | // this will add the current Verus chain name to subnames if it is not present | |
59 | // on both id and chain names | |
c8c684e9 | 60 | std::vector<std::string> CVDXF::ParseSubNames(const std::string &Name, std::string &ChainOut, bool displayfilter, bool addVerus) |
a88b514e | 61 | { |
62 | std::string nameCopy = Name; | |
63 | std::string invalidChars = "\\/:*?\"<>|"; | |
64 | if (displayfilter) | |
65 | { | |
66 | invalidChars += "\n\t\r\b\t\v\f\x1B"; | |
67 | } | |
68 | for (int i = 0; i < nameCopy.size(); i++) | |
69 | { | |
70 | if (invalidChars.find(nameCopy[i]) != std::string::npos) | |
71 | { | |
72 | return std::vector<std::string>(); | |
73 | } | |
74 | } | |
75 | ||
76 | std::vector<std::string> retNames; | |
77 | boost::split(retNames, nameCopy, boost::is_any_of("@")); | |
78 | if (!retNames.size() || retNames.size() > 2) | |
79 | { | |
80 | return std::vector<std::string>(); | |
81 | } | |
82 | ||
83 | bool explicitChain = false; | |
7c8e5e18 | 84 | if (retNames.size() == 2 && !retNames[1].empty()) |
a88b514e | 85 | { |
86 | ChainOut = retNames[1]; | |
87 | explicitChain = true; | |
88 | } | |
89 | ||
90 | nameCopy = retNames[0]; | |
91 | boost::split(retNames, nameCopy, boost::is_any_of(".")); | |
92 | ||
7c8e5e18 | 93 | if (retNames.size() && retNames.back().empty()) |
94 | { | |
95 | addVerus = false; | |
96 | retNames.pop_back(); | |
97 | nameCopy.pop_back(); | |
98 | } | |
99 | ||
a88b514e | 100 | int numRetNames = retNames.size(); |
101 | ||
03bfd9ae | 102 | std::string verusChainName = boost::to_lower_copy(VERUS_CHAINNAME); |
a88b514e | 103 | |
104 | if (addVerus) | |
105 | { | |
106 | if (explicitChain) | |
107 | { | |
108 | std::vector<std::string> chainOutNames; | |
109 | boost::split(chainOutNames, ChainOut, boost::is_any_of(".")); | |
110 | std::string lastChainOut = boost::to_lower_copy(chainOutNames.back()); | |
111 | ||
112 | if (lastChainOut != "" && lastChainOut != verusChainName) | |
113 | { | |
114 | chainOutNames.push_back(verusChainName); | |
115 | } | |
116 | else if (lastChainOut == "") | |
117 | { | |
118 | chainOutNames.pop_back(); | |
119 | } | |
120 | } | |
121 | ||
122 | std::string lastRetName = boost::to_lower_copy(retNames.back()); | |
123 | if (lastRetName != "" && lastRetName != verusChainName) | |
124 | { | |
125 | retNames.push_back(verusChainName); | |
126 | } | |
127 | else if (lastRetName == "") | |
128 | { | |
129 | retNames.pop_back(); | |
130 | } | |
131 | } | |
132 | ||
133 | for (int i = 0; i < retNames.size(); i++) | |
134 | { | |
135 | if (retNames[i].size() > KOMODO_ASSETCHAIN_MAXLEN - 1) | |
136 | { | |
137 | retNames[i] = std::string(retNames[i], 0, (KOMODO_ASSETCHAIN_MAXLEN - 1)); | |
138 | } | |
139 | // spaces are allowed, but no sub-name can have leading or trailing spaces | |
140 | if (!retNames[i].size() || retNames[i] != TrimTrailing(TrimLeading(retNames[i], ' '), ' ')) | |
141 | { | |
142 | return std::vector<std::string>(); | |
143 | } | |
144 | } | |
a88b514e | 145 | return retNames; |
146 | } | |
147 | ||
148 | // takes a multipart name, either complete or partially processed with a Parent hash, | |
149 | // hash its parent names into a parent ID and return the parent hash and cleaned, single name | |
150 | std::string CVDXF::CleanName(const std::string &Name, uint160 &Parent, bool displayfilter) | |
151 | { | |
152 | std::string chainName; | |
153 | std::vector<std::string> subNames = ParseSubNames(Name, chainName); | |
154 | ||
155 | if (!subNames.size()) | |
156 | { | |
157 | return ""; | |
158 | } | |
159 | ||
160 | if (!Parent.IsNull() && | |
161 | boost::to_lower_copy(subNames.back()) == boost::to_lower_copy(VERUS_CHAINNAME)) | |
162 | { | |
163 | subNames.pop_back(); | |
164 | } | |
165 | ||
166 | for (int i = subNames.size() - 1; i > 0; i--) | |
167 | { | |
168 | std::string parentNameStr = boost::algorithm::to_lower_copy(subNames[i]); | |
169 | const char *parentName = parentNameStr.c_str(); | |
170 | uint256 idHash; | |
171 | ||
172 | if (Parent.IsNull()) | |
173 | { | |
174 | idHash = Hash(parentName, parentName + parentNameStr.size()); | |
175 | } | |
176 | else | |
177 | { | |
178 | idHash = Hash(parentName, parentName + strlen(parentName)); | |
179 | idHash = Hash(Parent.begin(), Parent.end(), idHash.begin(), idHash.end()); | |
180 | } | |
181 | Parent = Hash160(idHash.begin(), idHash.end()); | |
182 | //printf("uint160 for parent %s: %s\n", parentName, Parent.GetHex().c_str()); | |
183 | } | |
184 | return subNames[0]; | |
185 | } | |
186 | ||
187 | uint160 CVDXF::GetID(const std::string &Name) | |
188 | { | |
189 | uint160 parent; | |
190 | std::string cleanName = CleanName(Name, parent); | |
191 | ||
192 | std::string subName = boost::algorithm::to_lower_copy(cleanName); | |
193 | const char *idName = subName.c_str(); | |
194 | //printf("hashing: %s, %s\n", idName, parent.GetHex().c_str()); | |
195 | ||
196 | uint256 idHash; | |
197 | if (parent.IsNull()) | |
198 | { | |
199 | idHash = Hash(idName, idName + strlen(idName)); | |
200 | } | |
201 | else | |
202 | { | |
203 | idHash = Hash(idName, idName + strlen(idName)); | |
204 | idHash = Hash(parent.begin(), parent.end(), idHash.begin(), idHash.end()); | |
205 | ||
206 | } | |
207 | return Hash160(idHash.begin(), idHash.end()); | |
208 | } | |
209 | ||
210 | uint160 CVDXF::GetID(const std::string &Name, uint160 &parent) | |
211 | { | |
212 | std::string cleanName = CleanName(Name, parent); | |
213 | ||
214 | std::string subName = boost::algorithm::to_lower_copy(cleanName); | |
215 | const char *idName = subName.c_str(); | |
216 | //printf("hashing: %s, %s\n", idName, parent.GetHex().c_str()); | |
217 | ||
218 | uint256 idHash; | |
219 | if (parent.IsNull()) | |
220 | { | |
221 | idHash = Hash(idName, idName + strlen(idName)); | |
222 | } | |
223 | else | |
224 | { | |
225 | idHash = Hash(idName, idName + strlen(idName)); | |
226 | idHash = Hash(parent.begin(), parent.end(), idHash.begin(), idHash.end()); | |
227 | } | |
228 | return Hash160(idHash.begin(), idHash.end()); | |
229 | } | |
230 | ||
231 | // calculate the data key for a name inside of a namespace | |
232 | // if the namespace is null, use VERUS_CHAINID | |
7c8e5e18 | 233 | uint160 CVDXF::GetDataKey(const std::string &keyName, uint160 &nameSpaceID) |
a88b514e | 234 | { |
7c8e5e18 | 235 | std::string keyCopy = keyName; |
236 | std::vector<std::string> addressParts; | |
237 | boost::split(addressParts, keyCopy, boost::is_any_of(":")); | |
238 | ||
239 | // if the first part of the address is a namespace, it is followed by double colon | |
240 | // namespace specifiers have no implicit root | |
241 | if (addressParts.size() > 2 && addressParts[1].empty()) | |
242 | { | |
243 | // look up to see if this is the private address of an ID. if not, or if the ID does not have a valid, Sapling address, it is invalid | |
244 | uint160 nsID = DecodeCurrencyName(addressParts[0] + "."); | |
245 | if (!nsID.IsNull()) | |
246 | { | |
247 | nameSpaceID = nsID; | |
248 | } | |
249 | keyCopy.clear(); | |
250 | for (int i = 2; i < addressParts.size(); i++) | |
251 | { | |
252 | keyCopy = i == 2 ? addressParts[i] : keyCopy + ":" + addressParts[i]; | |
253 | } | |
254 | } | |
255 | ||
a88b514e | 256 | if (nameSpaceID.IsNull()) |
257 | { | |
258 | nameSpaceID = VERUS_CHAINID; | |
259 | } | |
260 | uint160 parent = GetID(DATA_KEY_SEPARATOR, nameSpaceID); | |
7c8e5e18 | 261 | return GetID(keyCopy, parent); |
a88b514e | 262 | } |
263 | ||
264 | bool uni_get_bool(UniValue uv, bool def) | |
265 | { | |
266 | try | |
267 | { | |
268 | if (uv.isStr()) | |
269 | { | |
270 | std::string boolStr; | |
271 | if ((boolStr = uni_get_str(uv, def ? "true" : "false")) == "true" || boolStr == "1") | |
272 | { | |
273 | return true; | |
274 | } | |
275 | else if (boolStr == "false" || boolStr == "0") | |
276 | { | |
277 | return false; | |
278 | } | |
279 | return def; | |
280 | } | |
281 | else if (uv.isNum()) | |
282 | { | |
283 | return uv.get_int() != 0; | |
284 | } | |
285 | else | |
286 | { | |
287 | return uv.get_bool(); | |
288 | } | |
289 | return false; | |
290 | } | |
291 | catch(const std::exception& e) | |
292 | { | |
293 | return def; | |
294 | } | |
295 | } | |
296 | ||
297 | int32_t uni_get_int(UniValue uv, int32_t def) | |
298 | { | |
299 | try | |
300 | { | |
54f68f98 | 301 | if (!uv.isStr() && !uv.isNum()) |
4c26b35c | 302 | { |
54f68f98 | 303 | return def; |
4c26b35c | 304 | } |
54f68f98 | 305 | return (uv.isStr() ? atoi(uv.get_str()) : atoi(uv.getValStr())); |
a88b514e | 306 | } |
307 | catch(const std::exception& e) | |
308 | { | |
309 | return def; | |
310 | } | |
311 | } | |
312 | ||
313 | int64_t uni_get_int64(UniValue uv, int64_t def) | |
314 | { | |
315 | try | |
316 | { | |
54f68f98 | 317 | if (!uv.isStr() && !uv.isNum()) |
4c26b35c | 318 | { |
54f68f98 | 319 | return def; |
4c26b35c | 320 | } |
54f68f98 | 321 | return (uv.isStr() ? atoi64(uv.get_str()) : atoi64(uv.getValStr())); |
a88b514e | 322 | } |
323 | catch(const std::exception& e) | |
324 | { | |
325 | return def; | |
326 | } | |
327 | } | |
328 | ||
329 | std::string uni_get_str(UniValue uv, std::string def) | |
330 | { | |
331 | try | |
332 | { | |
333 | return uv.get_str(); | |
334 | } | |
335 | catch(const std::exception& e) | |
336 | { | |
337 | return def; | |
338 | } | |
339 | } | |
340 | ||
341 | std::vector<UniValue> uni_getValues(UniValue uv, std::vector<UniValue> def) | |
342 | { | |
343 | try | |
344 | { | |
345 | return uv.getValues(); | |
346 | } | |
347 | catch(const std::exception& e) | |
348 | { | |
349 | return def; | |
350 | } | |
351 | } | |
352 | ||
c8c684e9 | 353 | // this deserializes a vector into either a VDXF data object or a VDXF structured |
354 | // object, which may contain one or more VDXF data objects. | |
355 | // If the data in the sourceVector is not a recognized VDXF object, the returned | |
356 | // variant will be empty/invalid, otherwise, it will be a recognized VDXF object | |
357 | // or a VDXF structured object containing one or more recognized VDXF objects. | |
358 | VDXFData DeserializeVDXFData(const std::vector<unsigned char> &sourceVector) | |
359 | { | |
360 | CVDXF_StructuredData sData; | |
361 | ::FromVector(sourceVector, sData); | |
362 | if (sData.IsValid()) | |
363 | { | |
364 | return sData; | |
365 | } | |
366 | else | |
367 | { | |
368 | CVDXF_Data Data; | |
369 | ::FromVector(sourceVector, sData); | |
370 | if (Data.IsValid()) | |
371 | { | |
372 | return Data; | |
373 | } | |
374 | } | |
375 | return VDXFData(); | |
376 | } | |
377 | ||
378 | std::vector<unsigned char> SerializeVDXFData(const VDXFData &vdxfData) | |
379 | { | |
380 | return boost::apply_visitor(CSerializeVDXFData(), vdxfData); | |
381 | } | |
382 |