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 bool const 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 (binary)
272 {
273 auto&& obj = appendObject(array);
274 obj[jss::hash] = to_string(sle->key());
275 obj[jss::tx_blob] = serializeHex(*sle);
276 }
277 else if (expanded)
278 array.append(sle->getJson(JsonOptions::none));
279 else
280 array.append(to_string(sle->key()));
281 }
282}
283
284template <class Object>
285void
286fillJsonQueue(Object& json, LedgerFill const& fill)
287{
288 auto&& queueData = Json::setArray(json, jss::queue_data);
289 auto bBinary = isBinary(fill);
290 auto bExpanded = isExpanded(fill);
291
292 for (auto const& tx : fill.txQueue)
293 {
294 auto&& txJson = appendObject(queueData);
295 txJson[jss::fee_level] = to_string(tx.feeLevel);
296 if (tx.lastValid)
297 txJson[jss::LastLedgerSequence] = *tx.lastValid;
298
299 txJson[jss::fee] = to_string(tx.consequences.fee());
300 auto const spend =
301 tx.consequences.potentialSpend() + tx.consequences.fee();
302 txJson[jss::max_spend_drops] = to_string(spend);
303 txJson[jss::auth_change] = tx.consequences.isBlocker();
304
305 txJson[jss::account] = to_string(tx.account);
306 txJson["retries_remaining"] = tx.retriesRemaining;
307 txJson["preflight_result"] = transToken(tx.preflightResult);
308 if (tx.lastResult)
309 txJson["last_result"] = transToken(*tx.lastResult);
310
311 auto&& temp = fillJsonTx(fill, bBinary, bExpanded, tx.txn, nullptr);
312 if (fill.context->apiVersion > 1)
313 copyFrom(txJson, temp);
314 else
315 copyFrom(txJson[jss::tx], temp);
316 }
317}
318
319template <class Object>
320void
321fillJson(Object& json, LedgerFill const& fill)
322{
323 // TODO: what happens if bBinary and bExtracted are both set?
324 // Is there a way to report this back?
325 auto bFull = isFull(fill);
326 if (isBinary(fill))
327 fillJsonBinary(json, !fill.ledger.open(), fill.ledger.info());
328 else
329 fillJson(
330 json,
331 !fill.ledger.open(),
332 fill.ledger.info(),
333 bFull,
334 (fill.context ? fill.context->apiVersion
335 : RPC::apiMaximumSupportedVersion));
336
337 if (bFull || fill.options & LedgerFill::dumpTxrp)
338 fillJsonTx(json, fill);
339
340 if (bFull || fill.options & LedgerFill::dumpState)
341 fillJsonState(json, fill);
342}
343
344} // namespace
345
346void
347addJson(Json::Value& json, LedgerFill const& fill)
348{
349 auto&& object = Json::addObject(json, jss::ledger);
350 fillJson(object, fill);
351
352 if ((fill.options & LedgerFill::dumpQueue) && !fill.txQueue.empty())
353 fillJsonQueue(json, fill);
354}
355
357getJson(LedgerFill const& fill)
358{
359 Json::Value json;
360 fillJson(json, fill);
361 return json;
362}
363
364} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
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:45
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
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.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
bool getCloseAgree(LedgerHeader const &info)
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
Definition View.cpp:554
@ fhIGNORE_FREEZE
Definition View.h:77
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:264
LedgerHeader LedgerInfo
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
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)