xrpld
Loading...
Searching...
No Matches
ServerDefinitions.cpp
1#include <xrpld/rpc/handlers/server_info/ServerDefinitions.h>
2
3#include <xrpld/rpc/Context.h>
4
5#include <xrpl/basics/StringUtilities.h>
6#include <xrpl/basics/base_uint.h>
7#include <xrpl/json/json_value.h>
8#include <xrpl/json/json_writer.h>
9#include <xrpl/protocol/ErrorCodes.h>
10#include <xrpl/protocol/LedgerFormats.h>
11#include <xrpl/protocol/SField.h>
12#include <xrpl/protocol/TER.h>
13#include <xrpl/protocol/TxFlags.h>
14#include <xrpl/protocol/TxFormats.h>
15#include <xrpl/protocol/digest.h>
16#include <xrpl/protocol/jss.h>
17
18#include <boost/algorithm/string/replace.hpp>
19
20#include <cstddef>
21#include <cstdint>
22#include <map>
23#include <set>
24#include <string>
25#include <string_view>
26#include <unordered_map>
27
28namespace xrpl {
29
30namespace detail {
31
33{
34private:
35 static std::string
36 // translate e.g. STI_LEDGERENTRY to LedgerEntry
37 translate(std::string const& inp);
38
41
42public:
44
45 [[nodiscard]] bool
46 hashMatches(uint256 hash) const
47 {
48 return defsHash_ == hash;
49 }
50
51 [[nodiscard]] json::Value const&
52 get() const
53 {
54 return defs_;
55 }
56};
57
60{
61 auto replace = [&](std::string_view oldStr, std::string_view newStr) -> std::string {
62 std::string out = inp;
63 boost::replace_all(out, oldStr, newStr);
64 return out;
65 };
66
67 auto contains = [&](std::string_view s) -> bool { return inp.contains(s); };
68
69 if (contains("UINT"))
70 {
71 if (contains("512") || contains("384") || contains("256") || contains("192") ||
72 contains("160") || contains("128"))
73 {
74 return replace("UINT", "Hash");
75 }
76
77 return replace("UINT", "UInt");
78 }
79
81 {"OBJECT", "STObject"},
82 {"ARRAY", "STArray"},
83 {"ACCOUNT", "AccountID"},
84 {"LEDGERENTRY", "LedgerEntry"},
85 {"NOTPRESENT", "NotPresent"},
86 {"PATHSET", "PathSet"},
87 {"VL", "Blob"},
88 {"XCHAIN_BRIDGE", "XChainBridge"},
89 };
90
91 if (auto const& it = kReplacements.find(inp); it != kReplacements.end())
92 {
93 return std::string(it->second);
94 }
95
96 std::string out;
97 size_t pos = 0;
98 std::string inpToProcess = inp;
99
100 // convert snake_case to CamelCase
101 for (;;)
102 {
103 pos = inpToProcess.find('_');
104 if (pos == std::string::npos)
105 pos = inpToProcess.size();
106 std::string token = inpToProcess.substr(0, pos);
107 if (token.size() > 1)
108 {
109 token = toLower(token);
110 token[0] -= ('a' - 'A');
111 out += token;
112 }
113 else
114 {
115 out += token;
116 }
117 if (pos == inpToProcess.size())
118 break;
119 inpToProcess = inpToProcess.substr(pos + 1);
120 }
121 return out;
122};
123
125{
126 // populate SerializedTypeID names and values
127 defs_[jss::TYPES] = json::ValueType::Object;
128
129 defs_[jss::TYPES]["Done"] = -1;
130 std::map<int32_t, std::string> typeMap{{-1, "Done"}};
131 for (auto const& [rawName, typeValue] : kSTypeMap)
132 {
133 std::string const typeName = translate(std::string(rawName).substr(4) /* remove STI_ */);
134 defs_[jss::TYPES][typeName] = typeValue;
135 typeMap[typeValue] = typeName;
136 }
137
138 // populate LedgerEntryType names and values
139 defs_[jss::LEDGER_ENTRY_TYPES] = json::ValueType::Object;
140 defs_[jss::LEDGER_ENTRY_TYPES][jss::Invalid] = -1;
141
142 for (auto const& f : LedgerFormats::getInstance())
143 {
144 defs_[jss::LEDGER_ENTRY_TYPES][f.getName()] = f.getType();
145 }
146
147 // populate SField serialization data
148 defs_[jss::FIELDS] = json::ValueType::Array;
149
150 uint32_t i = 0;
151
152 {
154 a[0U] = "Invalid";
156 v[jss::nth] = -1;
157 v[jss::isVLEncoded] = false;
158 v[jss::isSerialized] = false;
159 v[jss::isSigningField] = false;
160 v[jss::type] = "Unknown";
161 a[1U] = v;
162 defs_[jss::FIELDS][i++] = a;
163 }
164
165 {
167 a[0U] = "ObjectEndMarker";
169 v[jss::nth] = 1;
170 v[jss::isVLEncoded] = false;
171 v[jss::isSerialized] = true;
172 v[jss::isSigningField] = true;
173 v[jss::type] = "STObject";
174 a[1U] = v;
175 defs_[jss::FIELDS][i++] = a;
176 }
177
178 {
180 a[0U] = "ArrayEndMarker";
182 v[jss::nth] = 1;
183 v[jss::isVLEncoded] = false;
184 v[jss::isSerialized] = true;
185 v[jss::isSigningField] = true;
186 v[jss::type] = "STArray";
187 a[1U] = v;
188 defs_[jss::FIELDS][i++] = a;
189 }
190
191 {
193 a[0U] = "taker_gets_funded";
195 v[jss::nth] = 258;
196 v[jss::isVLEncoded] = false;
197 v[jss::isSerialized] = false;
198 v[jss::isSigningField] = false;
199 v[jss::type] = "Amount";
200 a[1U] = v;
201 defs_[jss::FIELDS][i++] = a;
202 }
203
204 {
206 a[0U] = "taker_pays_funded";
208 v[jss::nth] = 259;
209 v[jss::isVLEncoded] = false;
210 v[jss::isSerialized] = false;
211 v[jss::isSigningField] = false;
212 v[jss::type] = "Amount";
213 a[1U] = v;
214 defs_[jss::FIELDS][i++] = a;
215 }
216
217 // copy into a sorted map to ensure deterministic output order (sorted by fieldCode)
218 static std::map<int, SField const*> const kSortedFields(
220
221 for (auto const& [code, field] : kSortedFields)
222 {
223 if (field->fieldName.empty())
224 continue;
225
227
228 int32_t const type = field->fieldType;
229
230 innerObj[jss::nth] = field->fieldValue;
231
232 // whether the field is variable-length encoded this means that the length is included
233 // before the content
234 innerObj[jss::isVLEncoded] =
235 (type == STI_VL || type == STI_ACCOUNT || type == STI_VECTOR256);
236 static_assert(
237 STI_VL == 7U && STI_ACCOUNT == 8U && STI_VECTOR256 == 19U,
238 "STI_VL, STI_ACCOUNT, STI_VECTOR256 must be 7, 8, 19 respectively");
239
240 // whether the field is included in serialization
241 innerObj[jss::isSerialized] =
242 (type < 10000 && field->fieldName != "hash" &&
243 field->fieldName !=
244 "index"); // hash, index, TRANSACTION, LEDGER_ENTRY, VALIDATION, METADATA
245
246 // whether the field is included in serialization when signing
247 innerObj[jss::isSigningField] = field->shouldInclude(false);
248
249 innerObj[jss::type] = typeMap[type];
250
252 innerArray[0U] = field->fieldName;
253 innerArray[1U] = innerObj;
254
255 defs_[jss::FIELDS][i++] = innerArray;
256 }
257
258 // populate TER code names and values
259 defs_[jss::TRANSACTION_RESULTS] = json::ValueType::Object;
260
261 for (auto const& [code, terInfo] : transResults())
262 {
263 defs_[jss::TRANSACTION_RESULTS][terInfo.first] = code;
264 }
265
266 // populate TxType names and values
267 defs_[jss::TRANSACTION_TYPES] = json::ValueType::Object;
268 defs_[jss::TRANSACTION_TYPES][jss::Invalid] = -1;
269 for (auto const& f : TxFormats::getInstance())
270 {
271 defs_[jss::TRANSACTION_TYPES][f.getName()] = f.getType();
272 }
273
274 // populate TxFormats
275 defs_[jss::TRANSACTION_FORMATS] = json::ValueType::Object;
276
277 defs_[jss::TRANSACTION_FORMATS][jss::common] = json::ValueType::Array;
278 auto txCommonFields = std::set<std::string>();
279 for (auto const& element : TxFormats::getCommonFields())
280 {
282 elementObj[jss::name] = element.sField().getName();
283 elementObj[jss::optionality] = element.style();
284 defs_[jss::TRANSACTION_FORMATS][jss::common].append(elementObj);
285 txCommonFields.insert(element.sField().getName());
286 }
287
288 for (auto const& format : TxFormats::getInstance())
289 {
290 auto const& soTemplate = format.getSOTemplate();
291 json::Value templateArray = json::ValueType::Array;
292 for (auto const& element : soTemplate)
293 {
294 if (txCommonFields.contains(element.sField().getName()))
295 continue; // skip common fields, already added
297 elementObj[jss::name] = element.sField().getName();
298 elementObj[jss::optionality] = element.style();
299 templateArray.append(elementObj);
300 }
301 defs_[jss::TRANSACTION_FORMATS][format.getName()] = templateArray;
302 }
303
304 // populate LedgerFormats
305 defs_[jss::LEDGER_ENTRY_FORMATS] = json::ValueType::Object;
306 defs_[jss::LEDGER_ENTRY_FORMATS][jss::common] = json::ValueType::Array;
307 auto ledgerCommonFields = std::set<std::string>();
308 for (auto const& element : LedgerFormats::getCommonFields())
309 {
311 elementObj[jss::name] = element.sField().getName();
312 elementObj[jss::optionality] = element.style();
313 defs_[jss::LEDGER_ENTRY_FORMATS][jss::common].append(elementObj);
314 ledgerCommonFields.insert(element.sField().getName());
315 }
316 for (auto const& format : LedgerFormats::getInstance())
317 {
318 auto const& soTemplate = format.getSOTemplate();
319 json::Value templateArray = json::ValueType::Array;
320 for (auto const& element : soTemplate)
321 {
322 if (ledgerCommonFields.contains(element.sField().getName()))
323 continue; // skip common fields, already added
325 elementObj[jss::name] = element.sField().getName();
326 elementObj[jss::optionality] = element.style();
327 templateArray.append(elementObj);
328 }
329 defs_[jss::LEDGER_ENTRY_FORMATS][format.getName()] = templateArray;
330 }
331
332 defs_[jss::TRANSACTION_FLAGS] = json::ValueType::Object;
333 for (auto const& [name, value] : getAllTxFlags())
334 {
336 for (auto const& [flagName, flagValue] : value)
337 {
338 txObj[flagName] = flagValue;
339 }
340 defs_[jss::TRANSACTION_FLAGS][name] = txObj;
341 }
342
343 defs_[jss::LEDGER_ENTRY_FLAGS] = json::ValueType::Object;
344 for (auto const& [name, value] : getAllLedgerFlags())
345 {
347 for (auto const& [flagName, flagValue] : value)
348 {
349 ledgerObj[flagName] = flagValue;
350 }
351 defs_[jss::LEDGER_ENTRY_FLAGS][name] = ledgerObj;
352 }
353
354 defs_[jss::ACCOUNT_SET_FLAGS] = json::ValueType::Object;
355 for (auto const& [name, value] : getAsfFlagMap())
356 {
357 defs_[jss::ACCOUNT_SET_FLAGS][name] = value;
358 }
359
360 // generate hash
361 {
364 defs_[jss::hash] = to_string(defsHash_);
365 }
366}
367
370{
371 static ServerDefinitions const kDefs{};
372 return kDefs;
373}
374
375} // namespace detail
376
377json::Value const&
382
385{
386 auto& params = context.params;
387
388 uint256 hash;
389 if (params.isMember(jss::hash))
390 {
391 if (!params[jss::hash].isString() || !hash.parseHex(params[jss::hash].asString()))
392 return rpc::invalidFieldError(jss::hash);
393 }
394
395 auto const& defs = detail::getDefinitions();
396 if (defs.hashMatches(hash))
397 {
399 jv[jss::hash] = to_string(hash);
400 return jv;
401 }
402 return defs.get();
403}
404
405} // namespace xrpl
Outputs a Value in JSON format without formatting (not human friendly).
Definition json_writer.h:37
std::string write(Value const &root) override
Represents a JSON value.
Definition json_value.h:117
Value & append(Value const &value)
Append value to array at the end.
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:525
static std::vector< SOElement > const & getCommonFields()
static LedgerFormats const & getInstance()
static std::unordered_map< int, SField const * > const & getKnownCodeToField()
Definition SField.h:292
An immutable linear range of bytes.
Definition Slice.h:28
static std::vector< SOElement > const & getCommonFields()
Definition TxFormats.cpp:13
static TxFormats const & getInstance()
Definition TxFormats.cpp:60
json::Value const & get() const
static std::string translate(std::string const &inp)
bool hashMatches(uint256 hash) const
T data(T... args)
T end(T... args)
T find(T... args)
JSON (JavaScript Object Notation).
Definition json_errors.h:5
@ Array
array value (ordered list)
Definition json_value.h:28
@ Object
object value (collection of name/value pairs).
Definition json_value.h:29
ServerDefinitions const & getDefinitions()
json::Value invalidFieldError(std::string const &name)
Definition ErrorCodes.h:285
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::string toLower(std::string str)
Fold ASCII upper case letters to lower case.
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition digest.h:215
json::Value const & getServerDefinitionsJson()
static std::map< std::string, int > const kSTypeMap
Definition SField.h:96
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:651
json::Value doServerDefinitions(rpc::JsonContext &)
FlagMapPairList const & getAllTxFlags()
Definition TxFlags.h:329
std::unordered_map< TERUnderlyingType, std::pair< char const *const, char const *const > > const & transResults()
Definition TER.cpp:14
std::vector< std::pair< std::string, LedgerFlagMap > > const & getAllLedgerFlags()
std::map< std::string, FlagValue > const & getAsfFlagMap()
Definition TxFlags.h:442
BaseUInt< 256 > uint256
Definition base_uint.h:580
T size(T... args)
json::Value params
Definition Context.h:51
T substr(T... args)