xrpld
Loading...
Searching...
No Matches
LedgerEntryHelpers.h
1#pragma once
2
3#include <xrpld/rpc/detail/RPCHelpers.h>
4
5#include <xrpl/basics/StringUtilities.h>
6#include <xrpl/basics/strHex.h>
7#include <xrpl/beast/core/LexicalCast.h>
8#include <xrpl/json/json_errors.h>
9#include <xrpl/protocol/ErrorCodes.h>
10#include <xrpl/protocol/Indexes.h>
11#include <xrpl/protocol/RPCErr.h>
12#include <xrpl/protocol/STXChainBridge.h>
13#include <xrpl/protocol/jss.h>
14
15#include <expected>
16#include <functional>
17
19
22{
24 json[jss::error] = err.value_or("malformedRequest");
25 json[jss::error_code] = RpcInvalidParams;
26 json[jss::error_message] = RPC::missingFieldMessage(std::string(field.cStr()));
27 return std::unexpected(json);
28}
29
31invalidFieldError(std::string const& err, json::StaticString const field, std::string const& type)
32{
34 json[jss::error] = err;
35 json[jss::error_code] = RpcInvalidParams;
36 json[jss::error_message] = RPC::expectedFieldMessage(field, type);
37 return std::unexpected(json);
38}
39
41malformedError(std::string const& err, std::string const& message)
42{
44 json[jss::error] = err;
45 json[jss::error_code] = RpcInvalidParams;
46 json[jss::error_message] = message;
47 return std::unexpected(json);
48}
49
50inline std::expected<bool, json::Value>
52 json::Value const& params,
54 std::optional<std::string> err = std::nullopt)
55{
56 for (auto const field : fields)
57 {
58 if (!params.isMember(field) || params[field].isNull())
59 {
60 return missingFieldError(field, err);
61 }
62 }
63 return true;
64}
65
66template <class T>
68parse(json::Value const& param);
69
70template <class T>
71std::expected<T, json::Value>
73 json::Value const& params,
74 json::StaticString const fieldName,
75 std::string const& err,
76 std::string const& expectedType)
77{
78 if (!params.isMember(fieldName) || params[fieldName].isNull())
79 {
80 return missingFieldError(fieldName);
81 }
82 if (auto obj = parse<T>(params[fieldName]))
83 {
84 return *obj;
85 }
86 return invalidFieldError(err, fieldName, expectedType);
87}
88
89template <>
91parse(json::Value const& param)
92{
93 if (!param.isString())
94 return std::nullopt;
95
96 auto const account = parseBase58<AccountID>(param.asString());
97 if (!account || account->isZero())
98 {
99 return std::nullopt;
100 }
101
102 return account;
103}
104
105inline std::expected<AccountID, json::Value>
107 json::Value const& params,
108 json::StaticString const fieldName,
109 std::string const& err)
110{
111 return required<AccountID>(params, fieldName, err, "AccountID");
112}
113
115parseHexBlob(json::Value const& param, std::size_t maxLength)
116{
117 if (!param.isString())
118 return std::nullopt;
119
120 auto blob = strUnHex(param.asString());
121 if (!blob || blob->empty() || blob->size() > maxLength)
122 return std::nullopt;
123
124 return blob;
125}
126
127inline std::expected<Blob, json::Value>
129 json::Value const& params,
130 json::StaticString const fieldName,
131 std::size_t maxLength,
132 std::string const& err)
133{
134 if (!params.isMember(fieldName) || params[fieldName].isNull())
135 {
136 return missingFieldError(fieldName);
137 }
138 if (auto blob = parseHexBlob(params[fieldName], maxLength))
139 {
140 return *blob;
141 }
142 return invalidFieldError(err, fieldName, "hex string");
143}
144
145template <>
147parse(json::Value const& param)
148{
149 if (param.isUInt() || (param.isInt() && param.asInt() >= 0))
150 return param.asUInt();
151
152 if (param.isString())
153 {
154 std::uint32_t v = 0;
155 if (beast::lexicalCastChecked(v, param.asString()))
156 return v;
157 }
158
159 return std::nullopt;
160}
161
162inline std::expected<std::uint32_t, json::Value>
164 json::Value const& params,
165 json::StaticString const fieldName,
166 std::string const& err)
167{
168 return required<std::uint32_t>(params, fieldName, err, "number");
169}
170
171template <>
173parse(json::Value const& param)
174{
175 uint256 uNodeIndex;
176 if (!param.isString() || !uNodeIndex.parseHex(param.asString()))
177 {
178 return std::nullopt;
179 }
180
181 return uNodeIndex;
182}
183
184inline std::expected<uint256, json::Value>
186 json::Value const& params,
187 json::StaticString const fieldName,
188 std::string const& err)
189{
190 return required<uint256>(params, fieldName, err, "Hash256");
191}
192
193template <>
195parse(json::Value const& param)
196{
197 uint192 field;
198 if (!param.isString() || !field.parseHex(param.asString()))
199 {
200 return std::nullopt;
201 }
202
203 return field;
204}
205
206inline std::expected<uint192, json::Value>
208 json::Value const& params,
209 json::StaticString const fieldName,
210 std::string const& err)
211{
212 return required<uint192>(params, fieldName, err, "Hash192");
213}
214
215template <>
217parse(json::Value const& param)
218{
219 try
220 {
221 return assetFromJson(param);
222 }
223 catch (std::runtime_error const&)
224 {
225 return std::nullopt;
226 }
227}
228
229inline std::expected<Asset, json::Value>
230requiredAsset(json::Value const& params, json::StaticString const fieldName, std::string const& err)
231{
232 return required<Asset>(params, fieldName, err, "Asset");
233}
234
235inline std::expected<STXChainBridge, json::Value>
237{
238 if (auto const value = hasRequired(
239 params,
240 {jss::LockingChainDoor,
241 jss::LockingChainIssue,
242 jss::IssuingChainDoor,
243 jss::IssuingChainIssue});
244 !value)
245 {
246 return std::unexpected(value.error());
247 }
248
249 auto const lockingChainDoor =
250 requiredAccountID(params, jss::LockingChainDoor, "malformedLockingChainDoor");
251 if (!lockingChainDoor)
252 {
253 return std::unexpected(lockingChainDoor.error());
254 }
255
256 auto const issuingChainDoor =
257 requiredAccountID(params, jss::IssuingChainDoor, "malformedIssuingChainDoor");
258 if (!issuingChainDoor)
259 {
260 return std::unexpected(issuingChainDoor.error());
261 }
262
263 Issue lockingChainIssue;
264 try
265 {
266 lockingChainIssue = issueFromJson(params[jss::LockingChainIssue]);
267 }
268 catch (std::runtime_error const& ex)
269 {
270 return invalidFieldError("malformedIssue", jss::LockingChainIssue, "Issue");
271 }
272
273 Issue issuingChainIssue;
274 try
275 {
276 issuingChainIssue = issueFromJson(params[jss::IssuingChainIssue]);
277 }
278 catch (std::runtime_error const& ex)
279 {
280 return invalidFieldError("malformedIssue", jss::IssuingChainIssue, "Issue");
281 }
282
283 return STXChainBridge(
284 *lockingChainDoor, lockingChainIssue, *issuingChainDoor, issuingChainIssue);
285}
286
287} // namespace xrpl::LedgerEntryHelpers
Lightweight wrapper to tag static string.
Definition json_value.h:44
Represents a JSON value.
Definition json_value.h:130
bool isNull() const
isNull() tests to see if this field is null.
bool isString() const
bool isUInt() const
bool isInt() const
UInt asUInt() const
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
Int asInt() const
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:507
A currency issued by an account.
Definition Issue.h:13
bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
JSON (JavaScript Object Notation).
Definition json_errors.h:5
@ Object
object value (collection of name/value pairs).
Definition json_value.h:26
std::optional< Blob > parseHexBlob(json::Value const &param, std::size_t maxLength)
std::unexpected< json::Value > missingFieldError(json::StaticString const field, std::optional< std::string > err=std::nullopt)
std::expected< T, json::Value > required(json::Value const &params, json::StaticString const fieldName, std::string const &err, std::string const &expectedType)
std::expected< uint256, json::Value > requiredUInt256(json::Value const &params, json::StaticString const fieldName, std::string const &err)
std::expected< STXChainBridge, json::Value > parseBridgeFields(json::Value const &params)
std::optional< T > parse(json::Value const &param)
std::unexpected< json::Value > malformedError(std::string const &err, std::string const &message)
std::expected< Blob, json::Value > requiredHexBlob(json::Value const &params, json::StaticString const fieldName, std::size_t maxLength, std::string const &err)
std::unexpected< json::Value > invalidFieldError(std::string const &err, json::StaticString const field, std::string const &type)
std::expected< Asset, json::Value > requiredAsset(json::Value const &params, json::StaticString const fieldName, std::string const &err)
std::expected< uint192, json::Value > requiredUInt192(json::Value const &params, json::StaticString const fieldName, std::string const &err)
std::expected< std::uint32_t, json::Value > requiredUInt32(json::Value const &params, json::StaticString const fieldName, std::string const &err)
std::expected< AccountID, json::Value > requiredAccountID(json::Value const &params, json::StaticString const fieldName, std::string const &err)
std::expected< bool, json::Value > hasRequired(json::Value const &params, std::initializer_list< json::StaticString > fields, std::optional< std::string > err=std::nullopt)
std::string missingFieldMessage(std::string const &name)
Definition ErrorCodes.h:225
std::string expectedFieldMessage(std::string const &name, std::string const &type)
Definition ErrorCodes.h:285
BaseUInt< 192 > uint192
Definition base_uint.h:563
Issue issueFromJson(json::Value const &v)
Definition Issue.cpp:89
@ RpcInvalidParams
Definition ErrorCodes.h:66
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Asset assetFromJson(json::Value const &jv)
Definition Asset.cpp:59
BaseUInt< 256 > uint256
Definition base_uint.h:562
T unexpected(T... args)