rippled
Loading...
Searching...
No Matches
LedgerToJson.cpp
1#include <xrpld/app/ledger/LedgerMaster.h>
2#include <xrpld/app/ledger/LedgerToJson.h>
3#include <xrpld/app/misc/DeliverMax.h>
4#include <xrpld/app/misc/TxQ.h>
5#include <xrpld/rpc/Context.h>
6#include <xrpld/rpc/DeliveredAmount.h>
7#include <xrpld/rpc/MPTokenIssuanceID.h>
8
9#include <xrpl/basics/base_uint.h>
10#include <xrpl/protocol/ApiVersion.h>
11#include <xrpl/protocol/jss.h>
12
13namespace ripple {
14
15namespace {
16
17bool
18isFull(LedgerFill const& fill)
19{
20 return fill.options & LedgerFill::full;
21}
22
23bool
24isExpanded(LedgerFill const& fill)
25{
26 return isFull(fill) || (fill.options & LedgerFill::expand);
27}
28
29bool
30isBinary(LedgerFill const& fill)
31{
32 return fill.options & LedgerFill::binary;
33}
34
35template <class Object>
36void
37fillJson(
38 Object& json,
39 bool closed,
40 LedgerInfo const& info,
41 bool bFull,
42 unsigned apiVersion)
43{
44 json[jss::parent_hash] = to_string(info.parentHash);
45 json[jss::ledger_index] = (apiVersion > 1)
46 ? Json::Value(info.seq)
47 : Json::Value(std::to_string(info.seq));
48
49 if (closed)
50 {
51 json[jss::closed] = true;
52 }
53 else if (!bFull)
54 {
55 json[jss::closed] = false;
56 return;
57 }
58
59 json[jss::ledger_hash] = to_string(info.hash);
60 json[jss::transaction_hash] = to_string(info.txHash);
61 json[jss::account_hash] = to_string(info.accountHash);
62 json[jss::total_coins] = to_string(info.drops);
63
64 json[jss::close_flags] = info.closeFlags;
65
66 // Always show fields that contribute to the ledger hash
67 json[jss::parent_close_time] =
68 info.parentCloseTime.time_since_epoch().count();
69 json[jss::close_time] = info.closeTime.time_since_epoch().count();
70 json[jss::close_time_resolution] = info.closeTimeResolution.count();
71
72 if (info.closeTime != NetClock::time_point{})
73 {
74 json[jss::close_time_human] = to_string(info.closeTime);
75 if (!getCloseAgree(info))
76 json[jss::close_time_estimated] = true;
77 json[jss::close_time_iso] = to_string_iso(info.closeTime);
78 }
79}
80
81template <class Object>
82void
83fillJsonBinary(Object& json, bool closed, LedgerInfo const& info)
84{
85 if (!closed)
86 json[jss::closed] = false;
87 else
88 {
89 json[jss::closed] = true;
90
91 Serializer s;
92 addRaw(info, s);
93 json[jss::ledger_data] = strHex(s.peekData());
94 }
95}
96
98fillJsonTx(
99 LedgerFill const& fill,
100 bool bBinary,
101 bool bExpanded,
104{
105 if (!bExpanded)
106 return to_string(txn->getTransactionID());
107
109 auto const txnType = txn->getTxnType();
110 if (bBinary)
111 {
112 txJson[jss::tx_blob] = serializeHex(*txn);
113 if (fill.context->apiVersion > 1)
114 txJson[jss::hash] = to_string(txn->getTransactionID());
115
116 auto const json_meta =
117 (fill.context->apiVersion > 1 ? jss::meta_blob : jss::meta);
118 if (stMeta)
119 txJson[json_meta] = serializeHex(*stMeta);
120 }
121 else if (fill.context->apiVersion > 1)
122 {
123 copyFrom(
124 txJson[jss::tx_json],
125 txn->getJson(JsonOptions::disable_API_prior_V2, false));
126 txJson[jss::hash] = to_string(txn->getTransactionID());
128 txJson[jss::tx_json], txnType, fill.context->apiVersion);
129
130 if (stMeta)
131 {
132 txJson[jss::meta] = stMeta->getJson(JsonOptions::none);
133
134 // If applicable, insert delivered amount
135 if (txnType == ttPAYMENT || txnType == ttCHECK_CASH)
137 txJson[jss::meta],
138 fill.ledger,
139 txn,
140 {txn->getTransactionID(), fill.ledger.seq(), *stMeta});
141
142 // If applicable, insert mpt issuance id
144 txJson[jss::meta],
145 txn,
146 {txn->getTransactionID(), fill.ledger.seq(), *stMeta});
147 }
148
149 if (!fill.ledger.open())
150 txJson[jss::ledger_hash] = to_string(fill.ledger.info().hash);
151
152 bool const validated =
153 fill.context->ledgerMaster.isValidated(fill.ledger);
154 txJson[jss::validated] = validated;
155 if (validated)
156 {
157 auto const seq = fill.ledger.seq();
158 txJson[jss::ledger_index] = seq;
159 if (fill.closeTime)
160 txJson[jss::close_time_iso] = to_string_iso(*fill.closeTime);
161 }
162 }
163 else
164 {
165 copyFrom(txJson, txn->getJson(JsonOptions::none));
166 RPC::insertDeliverMax(txJson, txnType, fill.context->apiVersion);
167 if (stMeta)
168 {
169 txJson[jss::metaData] = stMeta->getJson(JsonOptions::none);
170
171 // If applicable, insert delivered amount
172 if (txnType == ttPAYMENT || txnType == ttCHECK_CASH)
174 txJson[jss::metaData],
175 fill.ledger,
176 txn,
177 {txn->getTransactionID(), fill.ledger.seq(), *stMeta});
178
179 // If applicable, insert mpt issuance id
181 txJson[jss::metaData],
182 txn,
183 {txn->getTransactionID(), fill.ledger.seq(), *stMeta});
184 }
185 }
186
187 if ((fill.options & LedgerFill::ownerFunds) &&
188 txn->getTxnType() == ttOFFER_CREATE)
189 {
190 auto const account = txn->getAccountID(sfAccount);
191 auto const amount = txn->getFieldAmount(sfTakerGets);
192
193 // If the offer create is not self funded then add the
194 // owner balance
195 if (account != amount.getIssuer())
196 {
197 auto const ownerFunds = accountFunds(
198 fill.ledger,
199 account,
200 amount,
202 beast::Journal{beast::Journal::getNullSink()});
203 txJson[jss::owner_funds] = ownerFunds.getText();
204 }
205 }
206
207 return txJson;
208}
209
210template <class Object>
211void
212fillJsonTx(Object& json, LedgerFill const& fill)
213{
214 auto&& txns = setArray(json, jss::transactions);
215 auto bBinary = isBinary(fill);
216 auto bExpanded = isExpanded(fill);
217
218 try
219 {
220 auto appendAll = [&](auto const& txs) {
221 for (auto& i : txs)
222 {
223 txns.append(
224 fillJsonTx(fill, bBinary, bExpanded, i.first, i.second));
225 }
226 };
227
228 appendAll(fill.ledger.txs);
229 }
230 catch (std::exception const& ex)
231 {
232 // Nothing the user can do about this.
233 if (fill.context)
234 {
235 JLOG(fill.context->j.error())
236 << "Exception in " << __func__ << ": " << ex.what();
237 }
238 }
239}
240
241template <class Object>
242void
243fillJsonState(Object& json, LedgerFill const& fill)
244{
245 auto& ledger = fill.ledger;
246 auto&& array = Json::setArray(json, jss::accountState);
247 auto expanded = isExpanded(fill);
248 auto binary = isBinary(fill);
249
250 for (auto const& sle : ledger.sles)
251 {
252 if (binary)
253 {
254 auto&& obj = appendObject(array);
255 obj[jss::hash] = to_string(sle->key());
256 obj[jss::tx_blob] = serializeHex(*sle);
257 }
258 else if (expanded)
259 array.append(sle->getJson(JsonOptions::none));
260 else
261 array.append(to_string(sle->key()));
262 }
263}
264
265template <class Object>
266void
267fillJsonQueue(Object& json, LedgerFill const& fill)
268{
269 auto&& queueData = Json::setArray(json, jss::queue_data);
270 auto bBinary = isBinary(fill);
271 auto bExpanded = isExpanded(fill);
272
273 for (auto const& tx : fill.txQueue)
274 {
275 auto&& txJson = appendObject(queueData);
276 txJson[jss::fee_level] = to_string(tx.feeLevel);
277 if (tx.lastValid)
278 txJson[jss::LastLedgerSequence] = *tx.lastValid;
279
280 txJson[jss::fee] = to_string(tx.consequences.fee());
281 auto const spend =
282 tx.consequences.potentialSpend() + tx.consequences.fee();
283 txJson[jss::max_spend_drops] = to_string(spend);
284 txJson[jss::auth_change] = tx.consequences.isBlocker();
285
286 txJson[jss::account] = to_string(tx.account);
287 txJson["retries_remaining"] = tx.retriesRemaining;
288 txJson["preflight_result"] = transToken(tx.preflightResult);
289 if (tx.lastResult)
290 txJson["last_result"] = transToken(*tx.lastResult);
291
292 auto&& temp = fillJsonTx(fill, bBinary, bExpanded, tx.txn, nullptr);
293 if (fill.context->apiVersion > 1)
294 copyFrom(txJson, temp);
295 else
296 copyFrom(txJson[jss::tx], temp);
297 }
298}
299
300template <class Object>
301void
302fillJson(Object& json, LedgerFill const& fill)
303{
304 // TODO: what happens if bBinary and bExtracted are both set?
305 // Is there a way to report this back?
306 auto bFull = isFull(fill);
307 if (isBinary(fill))
308 fillJsonBinary(json, !fill.ledger.open(), fill.ledger.info());
309 else
310 fillJson(
311 json,
312 !fill.ledger.open(),
313 fill.ledger.info(),
314 bFull,
315 (fill.context ? fill.context->apiVersion
316 : RPC::apiMaximumSupportedVersion));
317
318 if (bFull || fill.options & LedgerFill::dumpTxrp)
319 fillJsonTx(json, fill);
320
321 if (bFull || fill.options & LedgerFill::dumpState)
322 fillJsonState(json, fill);
323}
324
325} // namespace
326
327void
328addJson(Json::Value& json, LedgerFill const& fill)
329{
330 auto&& object = Json::addObject(json, jss::ledger);
331 fillJson(object, fill);
332
333 if ((fill.options & LedgerFill::dumpQueue) && !fill.txQueue.empty())
334 fillJsonQueue(json, fill);
335}
336
338getJson(LedgerFill const& fill)
339{
340 Json::Value json;
341 fillJson(json, fill);
342 return json;
343}
344
345} // namespace ripple
Represents a JSON value.
Definition json_value.h:131
A generic endpoint for log messages.
Definition Journal.h:41
std::chrono::time_point< NetClock > time_point
Definition chrono.h:50
T fill(T... args)
@ objectValue
object value (collection of name/value pairs).
Definition json_value.h:27
Json::Value & setArray(Json::Value &, Json::StaticString const &key)
Add a new subarray at a named key in a Json object.
Definition Object.h:396
Json::Value & addObject(Json::Value &, Json::StaticString const &key)
Add a new subobject at a named key in a Json object.
Definition Object.h:408
Json::Value & appendObject(Json::Value &)
Append a new subobject to a Json object.
Definition Object.h:432
void copyFrom(Json::Value &to, Json::Value const &from)
Copy all the keys and values from one object into another.
Definition Object.cpp:213
void insertMPTokenIssuanceID(Json::Value &response, std::shared_ptr< STTx const > const &transaction, TxMeta const &transactionMeta)
void insertDeliveredAmount(Json::Value &meta, ReadView const &, std::shared_ptr< STTx const > const &serializedTx, TxMeta const &)
Add a delivered_amount field to the meta input/output parameter.
void insertDeliverMax(Json::Value &tx_json, TxType txnType, unsigned int apiVersion)
Copy Amount field to DeliverMax field in transaction output JSON.
Definition DeliverMax.cpp:9
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
bool getCloseAgree(LedgerHeader const &info)
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
Definition View.cpp:535
@ fhIGNORE_FREEZE
Definition View.h:58
std::string serializeHex(STObject const &o)
Serialize an object to a hex string.
Definition serialize.h:22
void addJson(Json::Value &json, LedgerFill const &fill)
Given a Ledger and options, fill a Json::Object or Json::Value with a description of the ledger.
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:11
std::string transToken(TER code)
Definition TER.cpp:245
LedgerHeader LedgerInfo
std::string to_string_iso(date::sys_time< Duration > tp)
Definition chrono.h:73
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
void addRaw(LedgerHeader const &, Serializer &, bool includeHash=false)
T to_string(T... args)
T what(T... args)