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