xrpld
Loading...
Searching...
No Matches
LedgerEntryHelpers.h
1#pragma once
2
3#include <xrpld/rpc/detail/RPCHelpers.h>
4
5#include <xrpl/basics/Blob.h>
6#include <xrpl/basics/StringUtilities.h>
7#include <xrpl/basics/base_uint.h>
8#include <xrpl/beast/core/LexicalCast.h>
9#include <xrpl/json/json_value.h>
10#include <xrpl/protocol/AccountID.h>
11#include <xrpl/protocol/Asset.h>
12#include <xrpl/protocol/ErrorCodes.h>
13#include <xrpl/protocol/Issue.h>
14#include <xrpl/protocol/STXChainBridge.h>
15#include <xrpl/protocol/jss.h>
16
17#include <cstddef>
18#include <cstdint>
19#include <expected>
20#include <initializer_list>
21#include <optional>
22#include <stdexcept>
23#include <string>
24
26
29{
31 json[jss::error] = err.value_or("malformedRequest");
32 json[jss::error_code] = RpcInvalidParams;
33 json[jss::error_message] = rpc::missingFieldMessage(std::string(field.cStr()));
34 return std::unexpected(json);
35}
36
38invalidFieldError(std::string const& err, json::StaticString const field, std::string const& type)
39{
41 json[jss::error] = err;
42 json[jss::error_code] = RpcInvalidParams;
43 json[jss::error_message] = rpc::expectedFieldMessage(field, type);
44 return std::unexpected(json);
45}
46
48malformedError(std::string const& err, std::string const& message)
49{
51 json[jss::error] = err;
52 json[jss::error_code] = RpcInvalidParams;
53 json[jss::error_message] = message;
54 return std::unexpected(json);
55}
56
57inline std::expected<bool, json::Value>
59 json::Value const& params,
61 std::optional<std::string> err = std::nullopt)
62{
63 for (auto const field : fields)
64 {
65 if (!params.isMember(field) || params[field].isNull())
66 {
67 return missingFieldError(field, err);
68 }
69 }
70 return true;
71}
72
73template <class T>
75parse(json::Value const& param);
76
77template <class T>
78std::expected<T, json::Value>
80 json::Value const& params,
81 json::StaticString const fieldName,
82 std::string const& err,
83 std::string const& expectedType)
84{
85 if (!params.isMember(fieldName) || params[fieldName].isNull())
86 {
87 return missingFieldError(fieldName);
88 }
89 if (auto obj = parse<T>(params[fieldName]))
90 {
91 return *obj;
92 }
93 return invalidFieldError(err, fieldName, expectedType);
94}
95
96template <>
98parse(json::Value const& param)
99{
100 if (!param.isString())
101 return std::nullopt;
102
103 auto const account = parseBase58<AccountID>(param.asString());
104 if (!account || account->isZero())
105 {
106 return std::nullopt;
107 }
108
109 return account;
110}
111
112inline std::expected<AccountID, json::Value>
114 json::Value const& params,
115 json::StaticString const fieldName,
116 std::string const& err)
117{
118 return required<AccountID>(params, fieldName, err, "AccountID");
119}
120
122parseHexBlob(json::Value const& param, std::size_t maxLength)
123{
124 if (!param.isString())
125 return std::nullopt;
126
127 auto blob = strUnHex(param.asString());
128 if (!blob || blob->empty() || blob->size() > maxLength)
129 return std::nullopt;
130
131 return blob;
132}
133
134inline std::expected<Blob, json::Value>
136 json::Value const& params,
137 json::StaticString const fieldName,
138 std::size_t maxLength,
139 std::string const& err)
140{
141 if (!params.isMember(fieldName) || params[fieldName].isNull())
142 {
143 return missingFieldError(fieldName);
144 }
145 if (auto blob = parseHexBlob(params[fieldName], maxLength))
146 {
147 return *blob;
148 }
149 return invalidFieldError(err, fieldName, "hex string");
150}
151
152template <>
154parse(json::Value const& param)
155{
156 if (param.isUInt() || (param.isInt() && param.asInt() >= 0))
157 return param.asUInt();
158
159 if (param.isString())
160 {
161 std::uint32_t v = 0;
162 if (beast::lexicalCastChecked(v, param.asString()))
163 return v;
164 }
165
166 return std::nullopt;
167}
168
169inline std::expected<std::uint32_t, json::Value>
171 json::Value const& params,
172 json::StaticString const fieldName,
173 std::string const& err)
174{
175 return required<std::uint32_t>(params, fieldName, err, "number");
176}
177
178template <>
180parse(json::Value const& param)
181{
182 uint256 uNodeIndex;
183 if (!param.isString() || !uNodeIndex.parseHex(param.asString()))
184 {
185 return std::nullopt;
186 }
187
188 return uNodeIndex;
189}
190
191inline std::expected<uint256, json::Value>
193 json::Value const& params,
194 json::StaticString const fieldName,
195 std::string const& err)
196{
197 return required<uint256>(params, fieldName, err, "Hash256");
198}
199
200template <>
202parse(json::Value const& param)
203{
204 uint192 field;
205 if (!param.isString() || !field.parseHex(param.asString()))
206 {
207 return std::nullopt;
208 }
209
210 return field;
211}
212
213inline std::expected<uint192, json::Value>
215 json::Value const& params,
216 json::StaticString const fieldName,
217 std::string const& err)
218{
219 return required<uint192>(params, fieldName, err, "Hash192");
220}
221
222template <>
224parse(json::Value const& param)
225{
226 try
227 {
228 return assetFromJson(param);
229 }
230 catch (std::runtime_error const&)
231 {
232 return std::nullopt;
233 }
234}
235
236inline std::expected<Asset, json::Value>
237requiredAsset(json::Value const& params, json::StaticString const fieldName, std::string const& err)
238{
239 return required<Asset>(params, fieldName, err, "Asset");
240}
241
242inline std::expected<STXChainBridge, json::Value>
244{
245 if (auto const value = hasRequired(
246 params,
247 {jss::LockingChainDoor,
248 jss::LockingChainIssue,
249 jss::IssuingChainDoor,
250 jss::IssuingChainIssue});
251 !value)
252 {
253 return std::unexpected(value.error());
254 }
255
256 auto const lockingChainDoor =
257 requiredAccountID(params, jss::LockingChainDoor, "malformedLockingChainDoor");
258 if (!lockingChainDoor)
259 {
260 return std::unexpected(lockingChainDoor.error());
261 }
262
263 auto const issuingChainDoor =
264 requiredAccountID(params, jss::IssuingChainDoor, "malformedIssuingChainDoor");
265 if (!issuingChainDoor)
266 {
267 return std::unexpected(issuingChainDoor.error());
268 }
269
270 Issue lockingChainIssue;
271 try
272 {
273 lockingChainIssue = issueFromJson(params[jss::LockingChainIssue]);
274 }
275 catch (std::runtime_error const& ex)
276 {
277 return invalidFieldError("malformedIssue", jss::LockingChainIssue, "Issue");
278 }
279
280 Issue issuingChainIssue;
281 try
282 {
283 issuingChainIssue = issueFromJson(params[jss::IssuingChainIssue]);
284 }
285 catch (std::runtime_error const& ex)
286 {
287 return invalidFieldError("malformedIssue", jss::IssuingChainIssue, "Issue");
288 }
289
290 return STXChainBridge(
291 *lockingChainDoor, lockingChainIssue, *issuingChainDoor, issuingChainIssue);
292}
293
294} // namespace xrpl::ledger_entry_helpers
Lightweight wrapper to tag static string.
Definition json_value.h:48
constexpr char const * cStr() const
Definition json_value.h:61
Represents a JSON value.
Definition json_value.h:117
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:525
A currency issued by an account.
Definition Issue.h:18
constexpr 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:29
std::optional< T > parse(json::Value const &param)
std::expected< AccountID, json::Value > requiredAccountID(json::Value const &params, json::StaticString const fieldName, std::string const &err)
std::expected< STXChainBridge, json::Value > parseBridgeFields(json::Value const &params)
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< uint256, json::Value > requiredUInt256(json::Value const &params, json::StaticString const fieldName, std::string const &err)
std::expected< Blob, json::Value > requiredHexBlob(json::Value const &params, json::StaticString const fieldName, std::size_t maxLength, std::string const &err)
std::expected< T, json::Value > required(json::Value const &params, json::StaticString const fieldName, std::string const &err, std::string const &expectedType)
std::unexpected< json::Value > malformedError(std::string const &err, std::string const &message)
std::expected< std::uint32_t, json::Value > requiredUInt32(json::Value const &params, json::StaticString const fieldName, std::string const &err)
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::unexpected< json::Value > invalidFieldError(std::string const &err, json::StaticString const field, std::string const &type)
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 expectedFieldMessage(std::string const &name, std::string const &type)
Definition ErrorCodes.h:297
std::string missingFieldMessage(std::string const &name)
Definition ErrorCodes.h:237
BaseUInt< 192 > uint192
Definition base_uint.h:581
Issue issueFromJson(json::Value const &v)
Definition Issue.cpp:89
@ RpcInvalidParams
Definition ErrorCodes.h:67
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:580
T unexpected(T... args)