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