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