xrpld
Loading...
Searching...
No Matches
LedgerData.cpp
1#include <xrpld/app/ledger/LedgerToJson.h>
2#include <xrpld/rpc/Context.h>
3#include <xrpld/rpc/GRPCHandlers.h>
4#include <xrpld/rpc/Role.h>
5#include <xrpld/rpc/detail/RPCHelpers.h>
6#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
7#include <xrpld/rpc/detail/Tuning.h>
8
9#include <xrpl/basics/base_uint.h>
10#include <xrpl/json/json_value.h>
11#include <xrpl/ledger/ReadView.h>
12#include <xrpl/protocol/ErrorCodes.h>
13#include <xrpl/protocol/Indexes.h>
14#include <xrpl/protocol/LedgerFormats.h>
15#include <xrpl/protocol/Serializer.h>
16#include <xrpl/protocol/jss.h>
17#include <xrpl/protocol/serialize.h>
18
19#include <grpcpp/support/status.h>
20#include <org/xrpl/rpc/v1/get_ledger_data.pb.h>
21
22#include <memory>
23#include <utility>
24
25namespace xrpl {
26
27// Get state nodes from a ledger
28// Inputs:
29// limit: integer, maximum number of entries
30// marker: opaque, resume point
31// binary: boolean, format
32// type: string // optional, defaults to all ledger node types
33// Outputs:
34// ledger_hash: chosen ledger's hash
35// ledger_index: chosen ledger's index
36// state: array of state nodes
37// marker: resume point, if any
38json::Value
40{
42 auto const& params = context.params;
43
44 auto jvResult = RPC::lookupLedger(lpLedger, context);
45 if (!lpLedger)
46 return jvResult;
47
48 bool const isMarker = params.isMember(jss::marker);
50 if (isMarker)
51 {
52 json::Value const& jMarker = params[jss::marker];
53 if (!(jMarker.isString() && key.parseHex(jMarker.asString())))
54 return RPC::expectedFieldError(jss::marker, "valid");
55 }
56
57 bool isBinary = false;
58 if (params.isMember(jss::binary))
59 {
60 if (!params[jss::binary].isBool())
61 return RPC::expectedFieldError(jss::binary, "boolean");
62 isBinary = params[jss::binary].asBool();
63 }
64
65 int limit = -1;
66 if (params.isMember(jss::limit))
67 {
68 json::Value const& jLimit = params[jss::limit];
69 if (!jLimit.isIntegral())
70 return RPC::expectedFieldError(jss::limit, "integer");
71
72 limit = jLimit.asInt();
73 }
74
75 auto maxLimit = RPC::Tuning::pageLength(isBinary);
76 if ((limit < 0) || ((limit > maxLimit) && (!isUnlimited(context.role))))
77 limit = maxLimit;
78
79 jvResult[jss::ledger_hash] = to_string(lpLedger->header().hash);
80 jvResult[jss::ledger_index] = lpLedger->header().seq;
81
82 if (!isMarker)
83 {
84 // Return base ledger data on first query
85 jvResult[jss::ledger] = getJson(LedgerFill(
86 *lpLedger, &context, isBinary ? static_cast<int>(LedgerFill::Options::Binary) : 0));
87 }
88
89 auto [rpcStatus, type] = RPC::chooseLedgerEntryType(params);
90 if (rpcStatus)
91 {
92 jvResult.clear();
93 rpcStatus.inject(jvResult);
94 return jvResult;
95 }
96 json::Value& nodes = jvResult[jss::state];
97 if (nodes.type() == json::ValueType::Null)
98 {
100 }
101
102 auto e = lpLedger->sles.end();
103 for (auto i = lpLedger->sles.upperBound(key); i != e; ++i)
104 {
105 auto sle = lpLedger->read(keylet::unchecked((*i)->key()));
106 if (limit-- <= 0)
107 {
108 // Stop processing before the current key.
109 auto k = sle->key();
110 jvResult[jss::marker] = to_string(--k);
111 break;
112 }
113
114 if (type == ltANY || sle->getType() == type)
115 {
116 if (isBinary)
117 {
119 entry[jss::data] = serializeHex(*sle);
120 entry[jss::index] = to_string(sle->key());
121 }
122 else
123 {
124 json::Value& entry = nodes.append(sle->getJson(JsonOptions::Values::None));
125 entry[jss::index] = to_string(sle->key());
126 }
127 }
128 }
129
130 return jvResult;
131}
132
135{
136 org::xrpl::rpc::v1::GetLedgerDataRequest const& request = context.params;
137 org::xrpl::rpc::v1::GetLedgerDataResponse response;
138 grpc::Status const status = grpc::Status::OK;
139
141 if (auto status = RPC::ledgerFromRequest(ledger, context))
142 {
143 grpc::Status errorStatus;
144 if (status.toErrorCode() == RpcInvalidParams)
145 {
146 errorStatus = grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, status.message());
147 }
148 else
149 {
150 errorStatus = grpc::Status(grpc::StatusCode::NOT_FOUND, status.message());
151 }
152 return {response, errorStatus};
153 }
154
155 uint256 startKey;
156 if (auto key = uint256::fromVoidChecked(request.marker()))
157 {
158 startKey = *key;
159 }
160 else if (!request.marker().empty())
161 {
162 grpc::Status const errorStatus{grpc::StatusCode::INVALID_ARGUMENT, "marker malformed"};
163 return {response, errorStatus};
164 }
165
166 auto e = ledger->sles.end();
167 if (!request.end_marker().empty())
168 {
169 auto const key = uint256::fromVoidChecked(request.end_marker());
170
171 if (!key)
172 return {response, {grpc::StatusCode::INVALID_ARGUMENT, "end marker malformed"}};
173
174 if (*key < startKey)
175 return {response, {grpc::StatusCode::INVALID_ARGUMENT, "end marker out of range"}};
176
177 e = ledger->sles.upperBound(*key);
178 }
179
180 int maxLimit = RPC::Tuning::pageLength(true);
181
182 for (auto i = ledger->sles.upperBound(startKey); i != e; ++i)
183 {
184 auto sle = ledger->read(keylet::unchecked((*i)->key()));
185 if (maxLimit-- <= 0)
186 {
187 // Stop processing before the current key.
188 auto k = sle->key();
189 --k;
190 response.set_marker(k.data(), k.size());
191 break;
192 }
193 auto stateObject = response.mutable_ledger_objects()->add_objects();
194 Serializer s;
195 sle->add(s);
196 stateObject->set_data(s.peekData().data(), s.getLength());
197 stateObject->set_key(sle->key().data(), sle->key().size());
198 }
199 return {response, status};
200}
201
202} // namespace xrpl
Represents a JSON value.
Definition json_value.h:130
bool isIntegral() const
bool isString() const
Value & append(Value const &value)
Append value to array at the end.
ValueType type() const
std::string asString() const
Returns the unquoted string value.
Int asInt() const
static std::optional< BaseUInt > fromVoidChecked(T const &from)
Definition base_uint.h:329
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:507
uint256 key_type
Definition ReadView.h:35
Blob const & peekData() const
Definition Serializer.h:176
int getLength() const
Definition Serializer.h:207
T data(T... args)
@ Array
array value (ordered list)
Definition json_value.h:25
@ Object
object value (collection of name/value pairs).
Definition json_value.h:26
@ Null
'null' value
Definition json_value.h:19
constexpr int pageLength(bool isBinary)
Maximum number of pages in a LedgerData response.
Status lookupLedger(std::shared_ptr< ReadView const > &ledger, JsonContext const &context, json::Value &result)
Looks up a ledger from a request and fills a json::Value with ledger data.
Status ledgerFromRequest(T &ledger, GRPCContext< R > const &context)
Retrieves a ledger from a gRPC request context.
std::pair< RPC::Status, LedgerEntryType > chooseLedgerEntryType(json::Value const &params)
Chooses the ledger entry type based on RPC parameters.
json::Value expectedFieldError(std::string const &name, std::string const &type)
Definition ErrorCodes.h:297
Keylet unchecked(uint256 const &key) noexcept
Any ledger entry.
Definition Indexes.cpp:351
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ RpcInvalidParams
Definition ErrorCodes.h:66
std::pair< org::xrpl::rpc::v1::GetLedgerDataResponse, grpc::Status > doLedgerDataGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetLedgerDataRequest > &context)
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
json::Value doLedgerData(RPC::JsonContext &)
std::string serializeHex(STObject const &o)
Serialize an object to a hex string.
Definition serialize.h:21
json::Value getJson(LedgerFill const &fill)
Return a new json::Value representing the ledger with given options.
@ ltANY
A special type, matching any ledger entry type.
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
Definition Role.cpp:115
BaseUInt< 256 > uint256
Definition base_uint.h:562
RequestType params
Definition Context.h:51
json::Value params
Definition Context.h:43