rippled
Loading...
Searching...
No Matches
LedgerEntryHelpers.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-2025 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/rpc/detail/RPCHelpers.h>
21
22#include <xrpl/basics/StringUtilities.h>
23#include <xrpl/basics/strHex.h>
24#include <xrpl/beast/core/LexicalCast.h>
25#include <xrpl/json/json_errors.h>
26#include <xrpl/protocol/ErrorCodes.h>
27#include <xrpl/protocol/Indexes.h>
28#include <xrpl/protocol/RPCErr.h>
29#include <xrpl/protocol/STXChainBridge.h>
30#include <xrpl/protocol/jss.h>
31
32#include <functional>
33
34namespace ripple {
35
36namespace LedgerEntryHelpers {
37
40 Json::StaticString const field,
42{
44 auto error = RPC::missing_field_message(std::string(field.c_str()));
45 json[jss::error] = err.value_or("malformedRequest");
46 json[jss::error_code] = rpcINVALID_PARAMS;
47 json[jss::error_message] = std::move(error);
48 return Unexpected(json);
49}
50
53 std::string const& err,
54 Json::StaticString const field,
55 std::string const& type)
56{
58 auto error = RPC::expected_field_message(field, type);
59 json[jss::error] = err;
60 json[jss::error_code] = rpcINVALID_PARAMS;
61 json[jss::error_message] = std::move(error);
62 return Unexpected(json);
63}
64
66malformedError(std::string const& err, std::string const& message)
67{
69 json[jss::error] = err;
70 json[jss::error_code] = rpcINVALID_PARAMS;
71 json[jss::error_message] = message;
72 return Unexpected(json);
73}
74
77 Json::Value const& params,
80{
81 for (auto const field : fields)
82 {
83 if (!params.isMember(field) || params[field].isNull())
84 {
85 return missingFieldError(field, err);
86 }
87 }
88 return true;
89}
90
91template <class T>
93parse(Json::Value const& param);
94
95template <class T>
98 Json::Value const& params,
99 Json::StaticString const fieldName,
100 std::string const& err,
101 std::string const& expectedType)
102{
103 if (!params.isMember(fieldName) || params[fieldName].isNull())
104 {
105 return missingFieldError(fieldName);
106 }
107 if (auto obj = parse<T>(params[fieldName]))
108 {
109 return *obj;
110 }
111 return invalidFieldError(err, fieldName, expectedType);
112}
113
114template <>
116parse(Json::Value const& param)
117{
118 if (!param.isString())
119 return std::nullopt;
120
121 auto const account = parseBase58<AccountID>(param.asString());
122 if (!account || account->isZero())
123 {
124 return std::nullopt;
125 }
126
127 return account;
128}
129
132 Json::Value const& params,
133 Json::StaticString const fieldName,
134 std::string const& err)
135{
136 return required<AccountID>(params, fieldName, err, "AccountID");
137}
138
140parseHexBlob(Json::Value const& param, std::size_t maxLength)
141{
142 if (!param.isString())
143 return std::nullopt;
144
145 auto const blob = strUnHex(param.asString());
146 if (!blob || blob->empty() || blob->size() > maxLength)
147 return std::nullopt;
148
149 return blob;
150}
151
154 Json::Value const& params,
155 Json::StaticString const fieldName,
156 std::size_t maxLength,
157 std::string const& err)
158{
159 if (!params.isMember(fieldName) || params[fieldName].isNull())
160 {
161 return missingFieldError(fieldName);
162 }
163 if (auto blob = parseHexBlob(params[fieldName], maxLength))
164 {
165 return *blob;
166 }
167 return invalidFieldError(err, fieldName, "hex string");
168}
169
170template <>
172parse(Json::Value const& param)
173{
174 if (param.isUInt() || (param.isInt() && param.asInt() >= 0))
175 return param.asUInt();
176
177 if (param.isString())
178 {
180 if (beast::lexicalCastChecked(v, param.asString()))
181 return v;
182 }
183
184 return std::nullopt;
185}
186
189 Json::Value const& params,
190 Json::StaticString const fieldName,
191 std::string const& err)
192{
193 return required<std::uint32_t>(params, fieldName, err, "number");
194}
195
196template <>
198parse(Json::Value const& param)
199{
200 uint256 uNodeIndex;
201 if (!param.isString() || !uNodeIndex.parseHex(param.asString()))
202 {
203 return std::nullopt;
204 }
205
206 return uNodeIndex;
207}
208
211 Json::Value const& params,
212 Json::StaticString const fieldName,
213 std::string const& err)
214{
215 return required<uint256>(params, fieldName, err, "Hash256");
216}
217
218template <>
220parse(Json::Value const& param)
221{
222 uint192 field;
223 if (!param.isString() || !field.parseHex(param.asString()))
224 {
225 return std::nullopt;
226 }
227
228 return field;
229}
230
233 Json::Value const& params,
234 Json::StaticString const fieldName,
235 std::string const& err)
236{
237 return required<uint192>(params, fieldName, err, "Hash192");
238}
239
242{
243 if (auto const value = hasRequired(
244 params,
245 {jss::LockingChainDoor,
246 jss::LockingChainIssue,
247 jss::IssuingChainDoor,
248 jss::IssuingChainIssue});
249 !value)
250 {
251 return Unexpected(value.error());
252 }
253
254 auto const lockingChainDoor = requiredAccountID(
255 params, jss::LockingChainDoor, "malformedLockingChainDoor");
256 if (!lockingChainDoor)
257 {
258 return Unexpected(lockingChainDoor.error());
259 }
260
261 auto const issuingChainDoor = requiredAccountID(
262 params, jss::IssuingChainDoor, "malformedIssuingChainDoor");
263 if (!issuingChainDoor)
264 {
265 return Unexpected(issuingChainDoor.error());
266 }
267
268 Issue lockingChainIssue;
269 try
270 {
271 lockingChainIssue = issueFromJson(params[jss::LockingChainIssue]);
272 }
273 catch (std::runtime_error const& ex)
274 {
275 return invalidFieldError(
276 "malformedIssue", jss::LockingChainIssue, "Issue");
277 }
278
279 Issue issuingChainIssue;
280 try
281 {
282 issuingChainIssue = issueFromJson(params[jss::IssuingChainIssue]);
283 }
284 catch (std::runtime_error const& ex)
285 {
286 return invalidFieldError(
287 "malformedIssue", jss::IssuingChainIssue, "Issue");
288 }
289
290 return STXChainBridge(
291 *lockingChainDoor,
292 lockingChainIssue,
293 *issuingChainDoor,
294 issuingChainIssue);
295}
296
297} // namespace LedgerEntryHelpers
298
299} // namespace ripple
Lightweight wrapper to tag static string.
Definition json_value.h:63
Represents a JSON value.
Definition json_value.h:149
Int asInt() const
bool isString() const
UInt asUInt() const
std::string asString() const
Returns the unquoted string value.
bool isUInt() const
bool isNull() const
isNull() tests to see if this field is null.
bool isMember(char const *key) const
Return true if the object has a member named key.
bool isInt() const
A currency issued by an account.
Definition Issue.h:33
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:503
T is_same_v
@ objectValue
object value (collection of name/value pairs).
Definition json_value.h:45
bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
std::optional< Blob > parseHexBlob(Json::Value const &param, std::size_t maxLength)
Expected< T, Json::Value > required(Json::Value const &params, Json::StaticString const fieldName, std::string const &err, std::string const &expectedType)
Expected< STXChainBridge, Json::Value > parseBridgeFields(Json::Value const &params)
Unexpected< Json::Value > malformedError(std::string const &err, std::string const &message)
Unexpected< Json::Value > invalidFieldError(std::string const &err, Json::StaticString const field, std::string const &type)
std::optional< T > parse(Json::Value const &param)
Expected< uint256, Json::Value > requiredUInt256(Json::Value const &params, Json::StaticString const fieldName, std::string const &err)
Unexpected< Json::Value > missingFieldError(Json::StaticString const field, std::optional< std::string > err=std::nullopt)
Expected< bool, Json::Value > hasRequired(Json::Value const &params, std::initializer_list< Json::StaticString > fields, std::optional< std::string > err=std::nullopt)
Expected< AccountID, Json::Value > requiredAccountID(Json::Value const &params, Json::StaticString const fieldName, std::string const &err)
Expected< std::uint32_t, Json::Value > requiredUInt32(Json::Value const &params, Json::StaticString const fieldName, std::string const &err)
Expected< uint192, Json::Value > requiredUInt192(Json::Value const &params, Json::StaticString const fieldName, std::string const &err)
Expected< Blob, Json::Value > requiredHexBlob(Json::Value const &params, Json::StaticString const fieldName, std::size_t maxLength, std::string const &err)
std::string missing_field_message(std::string const &name)
Definition ErrorCodes.h:277
std::string expected_field_message(std::string const &name, std::string const &type)
Definition ErrorCodes.h:337
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
@ rpcINVALID_PARAMS
Definition ErrorCodes.h:84
Issue issueFromJson(Json::Value const &v)
Definition Issue.cpp:95