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