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/LedgerToJson.h>
21 #include <ripple/app/main/Application.h>
22 #include <ripple/app/misc/DeliverMax.h>
23 #include <ripple/app/misc/TxQ.h>
24 #include <ripple/basics/base_uint.h>
25 #include <ripple/core/Pg.h>
26 #include <ripple/rpc/Context.h>
27 #include <ripple/rpc/DeliveredAmount.h>
28 
29 namespace ripple {
30 
31 namespace {
32 
33 bool
34 isFull(LedgerFill const& fill)
35 {
36  return fill.options & LedgerFill::full;
37 }
38 
39 bool
40 isExpanded(LedgerFill const& fill)
41 {
42  return isFull(fill) || (fill.options & LedgerFill::expand);
43 }
44 
45 bool
46 isBinary(LedgerFill const& fill)
47 {
48  return fill.options & LedgerFill::binary;
49 }
50 
51 template <class Object>
52 void
53 fillJson(Object& json, bool closed, LedgerInfo const& info, bool bFull)
54 {
55  json[jss::parent_hash] = to_string(info.parentHash);
56  json[jss::ledger_index] = to_string(info.seq);
57 
58  if (closed)
59  {
60  json[jss::closed] = true;
61  }
62  else if (!bFull)
63  {
64  json[jss::closed] = false;
65  return;
66  }
67 
68  json[jss::ledger_hash] = to_string(info.hash);
69  json[jss::transaction_hash] = to_string(info.txHash);
70  json[jss::account_hash] = to_string(info.accountHash);
71  json[jss::total_coins] = to_string(info.drops);
72 
73  json[jss::close_flags] = info.closeFlags;
74 
75  // Always show fields that contribute to the ledger hash
76  json[jss::parent_close_time] =
77  info.parentCloseTime.time_since_epoch().count();
78  json[jss::close_time] = info.closeTime.time_since_epoch().count();
79  json[jss::close_time_resolution] = info.closeTimeResolution.count();
80 
81  if (info.closeTime != NetClock::time_point{})
82  {
83  json[jss::close_time_human] = to_string(info.closeTime);
84  if (!getCloseAgree(info))
85  json[jss::close_time_estimated] = true;
86  }
87 }
88 
89 template <class Object>
90 void
91 fillJsonBinary(Object& json, bool closed, LedgerInfo const& info)
92 {
93  if (!closed)
94  json[jss::closed] = false;
95  else
96  {
97  json[jss::closed] = true;
98 
99  Serializer s;
100  addRaw(info, s);
101  json[jss::ledger_data] = strHex(s.peekData());
102  }
103 }
104 
106 fillJsonTx(
107  LedgerFill const& fill,
108  bool bBinary,
109  bool bExpanded,
110  std::shared_ptr<STTx const> const& txn,
111  std::shared_ptr<STObject const> const& stMeta)
112 {
113  if (!bExpanded)
114  return to_string(txn->getTransactionID());
115 
117  auto const txnType = txn->getTxnType();
118  if (bBinary)
119  {
120  txJson[jss::tx_blob] = serializeHex(*txn);
121  if (stMeta)
122  txJson[jss::meta] = serializeHex(*stMeta);
123  }
124  else
125  {
126  copyFrom(txJson, txn->getJson(JsonOptions::none));
127  RPC::insertDeliverMax(txJson, txnType, fill.context->apiVersion);
128  if (stMeta)
129  {
130  txJson[jss::metaData] = stMeta->getJson(JsonOptions::none);
131 
132  // If applicable, insert delivered amount
133  if (txnType == ttPAYMENT || txnType == ttCHECK_CASH)
135  txJson[jss::metaData],
136  fill.ledger,
137  txn,
138  {txn->getTransactionID(), fill.ledger.seq(), *stMeta});
139  }
140  }
141 
142  if ((fill.options & LedgerFill::ownerFunds) &&
143  txn->getTxnType() == ttOFFER_CREATE)
144  {
145  auto const account = txn->getAccountID(sfAccount);
146  auto const amount = txn->getFieldAmount(sfTakerGets);
147 
148  // If the offer create is not self funded then add the
149  // owner balance
150  if (account != amount.getIssuer())
151  {
152  auto const ownerFunds = accountFunds(
153  fill.ledger,
154  account,
155  amount,
157  beast::Journal{beast::Journal::getNullSink()});
158  txJson[jss::owner_funds] = ownerFunds.getText();
159  }
160  }
161 
162  return txJson;
163 }
164 
165 template <class Object>
166 void
167 fillJsonTx(Object& json, LedgerFill const& fill)
168 {
169  auto&& txns = setArray(json, jss::transactions);
170  auto bBinary = isBinary(fill);
171  auto bExpanded = isExpanded(fill);
172 
173  try
174  {
175  auto appendAll = [&](auto const& txs) {
176  for (auto& i : txs)
177  {
178  txns.append(
179  fillJsonTx(fill, bBinary, bExpanded, i.first, i.second));
180  }
181  };
182 
183  if (fill.context && fill.context->app.config().reporting())
184  {
185  appendAll(flatFetchTransactions(fill.ledger, fill.context->app));
186  }
187  else
188  {
189  appendAll(fill.ledger.txs);
190  }
191  }
192  catch (std::exception const& ex)
193  {
194  // Nothing the user can do about this.
195  if (fill.context)
196  {
197  JLOG(fill.context->j.error())
198  << "Exception in " << __func__ << ": " << ex.what();
199  }
200  }
201 }
202 
203 template <class Object>
204 void
205 fillJsonState(Object& json, LedgerFill const& fill)
206 {
207  auto& ledger = fill.ledger;
208  auto&& array = Json::setArray(json, jss::accountState);
209  auto expanded = isExpanded(fill);
210  auto binary = isBinary(fill);
211 
212  for (auto const& sle : ledger.sles)
213  {
214  if (fill.type == ltANY || sle->getType() == fill.type)
215  {
216  if (binary)
217  {
218  auto&& obj = appendObject(array);
219  obj[jss::hash] = to_string(sle->key());
220  obj[jss::tx_blob] = serializeHex(*sle);
221  }
222  else if (expanded)
223  array.append(sle->getJson(JsonOptions::none));
224  else
225  array.append(to_string(sle->key()));
226  }
227  }
228 }
229 
230 template <class Object>
231 void
232 fillJsonQueue(Object& json, LedgerFill const& fill)
233 {
234  auto&& queueData = Json::setArray(json, jss::queue_data);
235  auto bBinary = isBinary(fill);
236  auto bExpanded = isExpanded(fill);
237 
238  for (auto const& tx : fill.txQueue)
239  {
240  auto&& txJson = appendObject(queueData);
241  txJson[jss::fee_level] = to_string(tx.feeLevel);
242  if (tx.lastValid)
243  txJson[jss::LastLedgerSequence] = *tx.lastValid;
244 
245  txJson[jss::fee] = to_string(tx.consequences.fee());
246  auto const spend =
247  tx.consequences.potentialSpend() + tx.consequences.fee();
248  txJson[jss::max_spend_drops] = to_string(spend);
249  txJson[jss::auth_change] = tx.consequences.isBlocker();
250 
251  txJson[jss::account] = to_string(tx.account);
252  txJson["retries_remaining"] = tx.retriesRemaining;
253  txJson["preflight_result"] = transToken(tx.preflightResult);
254  if (tx.lastResult)
255  txJson["last_result"] = transToken(*tx.lastResult);
256 
257  txJson[jss::tx] = fillJsonTx(fill, bBinary, bExpanded, tx.txn, nullptr);
258  }
259 }
260 
261 template <class Object>
262 void
263 fillJson(Object& json, LedgerFill const& fill)
264 {
265  // TODO: what happens if bBinary and bExtracted are both set?
266  // Is there a way to report this back?
267  auto bFull = isFull(fill);
268  if (isBinary(fill))
269  fillJsonBinary(json, !fill.ledger.open(), fill.ledger.info());
270  else
271  fillJson(json, !fill.ledger.open(), fill.ledger.info(), bFull);
272 
273  if (bFull || fill.options & LedgerFill::dumpTxrp)
274  fillJsonTx(json, fill);
275 
276  if (bFull || fill.options & LedgerFill::dumpState)
277  fillJsonState(json, fill);
278 }
279 
280 } // namespace
281 
282 void
283 addJson(Json::Value& json, LedgerFill const& fill)
284 {
285  auto&& object = Json::addObject(json, jss::ledger);
286  fillJson(object, fill);
287 
288  if ((fill.options & LedgerFill::dumpQueue) && !fill.txQueue.empty())
289  fillJsonQueue(json, fill);
290 }
291 
293 getJson(LedgerFill const& fill)
294 {
295  Json::Value json;
296  fillJson(json, fill);
297  return json;
298 }
299 
300 } // namespace ripple
ripple::STTx::getTxnType
TxType getTxnType() const
Definition: STTx.h:179
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:47
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:53
ripple::LedgerInfo
LedgerHeader LedgerInfo
Definition: LedgerHeader.h:79
ripple::transToken
std::string transToken(TER code)
Definition: TER.cpp:241
ripple::LedgerFill::expand
@ expand
Definition: LedgerToJson.h:49
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::JsonOptions::none
@ none
ripple::LedgerFill::full
@ full
Definition: LedgerToJson.h:50
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:229
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:191
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:51
ripple::getJson
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
Definition: LedgerToJson.cpp:293
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::addRaw
void addRaw(LedgerHeader const &info, Serializer &s, bool includeHash)
Definition: protocol/impl/LedgerHeader.cpp:25
ripple::LedgerFill::ownerFunds
@ ownerFunds
Definition: LedgerToJson.h:52
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:283
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:48
ripple::STObject::getJson
Json::Value getJson(JsonOptions options) const override
Definition: STObject.cpp:731
ripple::LedgerFill
Definition: LedgerToJson.h:34
ripple::NetClock::time_point
std::chrono::time_point< NetClock > time_point
Definition: chrono.h:56
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