rippled
LedgerEntry.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2014 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/main/Application.h>
21 #include <ripple/basics/StringUtilities.h>
22 #include <ripple/basics/strHex.h>
23 #include <ripple/ledger/ReadView.h>
24 #include <ripple/net/RPCErr.h>
25 #include <ripple/protocol/ErrorCodes.h>
26 #include <ripple/protocol/Indexes.h>
27 #include <ripple/protocol/jss.h>
28 #include <ripple/rpc/Context.h>
29 #include <ripple/rpc/impl/RPCHelpers.h>
30 
31 namespace ripple {
32 
33 // {
34 // ledger_hash : <ledger>
35 // ledger_index : <ledger_index>
36 // ...
37 // }
40 {
42  auto jvResult = RPC::lookupLedger(lpLedger, context);
43 
44  if (!lpLedger)
45  return jvResult;
46 
47  uint256 uNodeIndex;
48  bool bNodeBinary = false;
49  LedgerEntryType expectedType = ltANY;
50 
51  if (context.params.isMember(jss::index))
52  {
53  uNodeIndex.SetHex(context.params[jss::index].asString());
54  }
55  else if (context.params.isMember(jss::account_root))
56  {
57  expectedType = ltACCOUNT_ROOT;
58  auto const account = parseBase58<AccountID>(
59  context.params[jss::account_root].asString());
60  if (!account || account->isZero())
61  jvResult[jss::error] = "malformedAddress";
62  else
63  uNodeIndex = keylet::account(*account).key;
64  }
65  else if (context.params.isMember(jss::check))
66  {
67  expectedType = ltCHECK;
68  uNodeIndex.SetHex(context.params[jss::check].asString());
69  }
70  else if (context.params.isMember(jss::deposit_preauth))
71  {
72  expectedType = ltDEPOSIT_PREAUTH;
73 
74  if (!context.params[jss::deposit_preauth].isObject())
75  {
76  if (!context.params[jss::deposit_preauth].isString() ||
77  !uNodeIndex.SetHex(
78  context.params[jss::deposit_preauth].asString()))
79  {
80  uNodeIndex = beast::zero;
81  jvResult[jss::error] = "malformedRequest";
82  }
83  }
84  else if (
85  !context.params[jss::deposit_preauth].isMember(jss::owner) ||
86  !context.params[jss::deposit_preauth][jss::owner].isString() ||
87  !context.params[jss::deposit_preauth].isMember(jss::authorized) ||
88  !context.params[jss::deposit_preauth][jss::authorized].isString())
89  {
90  jvResult[jss::error] = "malformedRequest";
91  }
92  else
93  {
94  auto const owner = parseBase58<AccountID>(
95  context.params[jss::deposit_preauth][jss::owner].asString());
96 
97  auto const authorized = parseBase58<AccountID>(
98  context.params[jss::deposit_preauth][jss::authorized]
99  .asString());
100 
101  if (!owner)
102  jvResult[jss::error] = "malformedOwner";
103  else if (!authorized)
104  jvResult[jss::error] = "malformedAuthorized";
105  else
106  uNodeIndex = keylet::depositPreauth(*owner, *authorized).key;
107  }
108  }
109  else if (context.params.isMember(jss::directory))
110  {
111  expectedType = ltDIR_NODE;
112  if (context.params[jss::directory].isNull())
113  {
114  jvResult[jss::error] = "malformedRequest";
115  }
116  else if (!context.params[jss::directory].isObject())
117  {
118  uNodeIndex.SetHex(context.params[jss::directory].asString());
119  }
120  else if (
121  context.params[jss::directory].isMember(jss::sub_index) &&
122  !context.params[jss::directory][jss::sub_index].isIntegral())
123  {
124  jvResult[jss::error] = "malformedRequest";
125  }
126  else
127  {
128  std::uint64_t uSubIndex =
129  context.params[jss::directory].isMember(jss::sub_index)
130  ? context.params[jss::directory][jss::sub_index].asUInt()
131  : 0;
132 
133  if (context.params[jss::directory].isMember(jss::dir_root))
134  {
135  if (context.params[jss::directory].isMember(jss::owner))
136  {
137  // May not specify both dir_root and owner.
138  jvResult[jss::error] = "malformedRequest";
139  }
140  else
141  {
142  uint256 uDirRoot;
143  uDirRoot.SetHex(
144  context.params[jss::directory][jss::dir_root]
145  .asString());
146 
147  uNodeIndex = keylet::page(uDirRoot, uSubIndex).key;
148  }
149  }
150  else if (context.params[jss::directory].isMember(jss::owner))
151  {
152  auto const ownerID = parseBase58<AccountID>(
153  context.params[jss::directory][jss::owner].asString());
154 
155  if (!ownerID)
156  {
157  jvResult[jss::error] = "malformedAddress";
158  }
159  else
160  {
161  uNodeIndex =
162  keylet::page(keylet::ownerDir(*ownerID), uSubIndex).key;
163  }
164  }
165  else
166  {
167  jvResult[jss::error] = "malformedRequest";
168  }
169  }
170  }
171  else if (context.params.isMember(jss::escrow))
172  {
173  expectedType = ltESCROW;
174  if (!context.params[jss::escrow].isObject())
175  {
176  uNodeIndex.SetHex(context.params[jss::escrow].asString());
177  }
178  else if (
179  !context.params[jss::escrow].isMember(jss::owner) ||
180  !context.params[jss::escrow].isMember(jss::seq) ||
181  !context.params[jss::escrow][jss::seq].isIntegral())
182  {
183  jvResult[jss::error] = "malformedRequest";
184  }
185  else
186  {
187  auto const id = parseBase58<AccountID>(
188  context.params[jss::escrow][jss::owner].asString());
189  if (!id)
190  jvResult[jss::error] = "malformedOwner";
191  else
192  uNodeIndex =
194  *id, context.params[jss::escrow][jss::seq].asUInt())
195  .key;
196  }
197  }
198  else if (context.params.isMember(jss::offer))
199  {
200  expectedType = ltOFFER;
201  if (!context.params[jss::offer].isObject())
202  {
203  uNodeIndex.SetHex(context.params[jss::offer].asString());
204  }
205  else if (
206  !context.params[jss::offer].isMember(jss::account) ||
207  !context.params[jss::offer].isMember(jss::seq) ||
208  !context.params[jss::offer][jss::seq].isIntegral())
209  {
210  jvResult[jss::error] = "malformedRequest";
211  }
212  else
213  {
214  auto const id = parseBase58<AccountID>(
215  context.params[jss::offer][jss::account].asString());
216  if (!id)
217  jvResult[jss::error] = "malformedAddress";
218  else
219  uNodeIndex =
221  *id, context.params[jss::offer][jss::seq].asUInt())
222  .key;
223  }
224  }
225  else if (context.params.isMember(jss::payment_channel))
226  {
227  expectedType = ltPAYCHAN;
228  uNodeIndex.SetHex(context.params[jss::payment_channel].asString());
229  }
230  else if (context.params.isMember(jss::ripple_state))
231  {
232  expectedType = ltRIPPLE_STATE;
233  Currency uCurrency;
234  Json::Value jvRippleState = context.params[jss::ripple_state];
235 
236  if (!jvRippleState.isObject() ||
237  !jvRippleState.isMember(jss::currency) ||
238  !jvRippleState.isMember(jss::accounts) ||
239  !jvRippleState[jss::accounts].isArray() ||
240  2 != jvRippleState[jss::accounts].size() ||
241  !jvRippleState[jss::accounts][0u].isString() ||
242  !jvRippleState[jss::accounts][1u].isString() ||
243  (jvRippleState[jss::accounts][0u].asString() ==
244  jvRippleState[jss::accounts][1u].asString()))
245  {
246  jvResult[jss::error] = "malformedRequest";
247  }
248  else
249  {
250  auto const id1 = parseBase58<AccountID>(
251  jvRippleState[jss::accounts][0u].asString());
252  auto const id2 = parseBase58<AccountID>(
253  jvRippleState[jss::accounts][1u].asString());
254  if (!id1 || !id2)
255  {
256  jvResult[jss::error] = "malformedAddress";
257  }
258  else if (!to_currency(
259  uCurrency, jvRippleState[jss::currency].asString()))
260  {
261  jvResult[jss::error] = "malformedCurrency";
262  }
263  else
264  {
265  uNodeIndex = keylet::line(*id1, *id2, uCurrency).key;
266  }
267  }
268  }
269  else if (context.params.isMember(jss::ticket))
270  {
271  expectedType = ltTICKET;
272  if (!context.params[jss::ticket].isObject())
273  {
274  uNodeIndex.SetHex(context.params[jss::ticket].asString());
275  }
276  else if (
277  !context.params[jss::ticket].isMember(jss::account) ||
278  !context.params[jss::ticket].isMember(jss::ticket_seq) ||
279  !context.params[jss::ticket][jss::ticket_seq].isIntegral())
280  {
281  jvResult[jss::error] = "malformedRequest";
282  }
283  else
284  {
285  auto const id = parseBase58<AccountID>(
286  context.params[jss::ticket][jss::account].asString());
287  if (!id)
288  jvResult[jss::error] = "malformedAddress";
289  else
290  uNodeIndex = getTicketIndex(
291  *id, context.params[jss::ticket][jss::ticket_seq].asUInt());
292  }
293  }
294  else
295  {
296  jvResult[jss::error] = "unknownOption";
297  }
298 
299  if (uNodeIndex.isNonZero())
300  {
301  auto const sleNode = lpLedger->read(keylet::unchecked(uNodeIndex));
302  if (context.params.isMember(jss::binary))
303  bNodeBinary = context.params[jss::binary].asBool();
304 
305  if (!sleNode)
306  {
307  // Not found.
308  jvResult[jss::error] = "entryNotFound";
309  }
310  else if (
311  (expectedType != ltANY) && (expectedType != sleNode->getType()))
312  {
313  jvResult[jss::error] = "malformedRequest";
314  }
315  else if (bNodeBinary)
316  {
317  Serializer s;
318 
319  sleNode->add(s);
320 
321  jvResult[jss::node_binary] = strHex(s.peekData());
322  jvResult[jss::index] = to_string(uNodeIndex);
323  }
324  else
325  {
326  jvResult[jss::node] = sleNode->getJson(JsonOptions::none);
327  jvResult[jss::index] = to_string(uNodeIndex);
328  }
329  }
330 
331  return jvResult;
332 }
333 
334 } // namespace ripple
ripple::keylet::ownerDir
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:299
ripple::to_currency
bool to_currency(Currency &currency, std::string const &code)
Tries to convert a string to a Currency, returns true on success.
Definition: UintTypes.cpp:80
ripple::RPC::JsonContext
Definition: Context.h:53
ripple::doLedgerEntry
Json::Value doLedgerEntry(RPC::JsonContext &)
Definition: LedgerEntry.cpp:39
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1027
std::shared_ptr
STL class.
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1009
ripple::base_uint::isNonZero
bool isNonZero() const
Definition: base_uint.h:480
ripple::ltESCROW
@ ltESCROW
Definition: LedgerFormats.h:80
ripple::ltANY
@ ltANY
Special type, anything This is used when the type in the Keylet is unknown, such as when building met...
Definition: LedgerFormats.h:41
ripple::keylet::offer
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Definition: Indexes.cpp:218
Json::Value::isNull
bool isNull() const
isNull() tests to see if this field is null.
Definition: json_value.cpp:967
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
ripple::RPC::lookupLedger
Status lookupLedger(std::shared_ptr< ReadView const > &ledger, JsonContext &context, Json::Value &result)
Look up a ledger from a request and fill a Json::Result with the data representing a ledger.
Definition: RPCHelpers.cpp:487
ripple::getTicketIndex
uint256 getTicketIndex(AccountID const &account, std::uint32_t ticketSeq)
Definition: Indexes.cpp:111
ripple::ltTICKET
@ ltTICKET
Definition: LedgerFormats.h:68
ripple::ltCHECK
@ ltCHECK
Definition: LedgerFormats.h:85
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:619
ripple::Keylet::key
uint256 key
Definition: Keylet.h:41
ripple::base_uint< 256 >
ripple::keylet::escrow
Keylet escrow(AccountID const &src, std::uint32_t seq) noexcept
An escrow entry.
Definition: Indexes.cpp:314
ripple::base_uint::isZero
bool isZero() const
Definition: base_uint.h:475
ripple::authorized
static bool authorized(Port const &port, std::map< std::string, std::string > const &h)
Definition: ServerHandlerImp.cpp:85
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:129
ripple::JsonOptions::none
@ none
ripple::keylet::page
Keylet page(uint256 const &key, std::uint64_t index) noexcept
A page in a directory.
Definition: Indexes.cpp:305
ripple::base_uint::SetHex
bool SetHex(const char *psz, bool bStrict=false)
Parse a hex string into a base_uint The input can be:
Definition: base_uint.h:406
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
std::uint64_t
ripple::keylet::line
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition: Indexes.cpp:189
ripple::ltDEPOSIT_PREAUTH
@ ltDEPOSIT_PREAUTH
Definition: LedgerFormats.h:87
ripple::keylet::unchecked
Keylet unchecked(uint256 const &key) noexcept
Any ledger entry.
Definition: Indexes.cpp:293
ripple::ReadView::read
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1015
ripple::Serializer
Definition: Serializer.h:39
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::ltRIPPLE_STATE
@ ltRIPPLE_STATE
Definition: LedgerFormats.h:66
ripple::LedgerEntryType
LedgerEntryType
Ledger entry types.
Definition: LedgerFormats.h:36
ripple::Serializer::peekData
Blob const & peekData() const
Definition: Serializer.h:166
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:545
Json::Value::isIntegral
bool isIntegral() const
Definition: json_value.cpp:991
ripple::ltPAYCHAN
@ ltPAYCHAN
Definition: LedgerFormats.h:83
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:67
ripple::ltDIR_NODE
@ ltDIR_NODE
Directory node.
Definition: LedgerFormats.h:64
ripple::ltOFFER
@ ltOFFER
Definition: LedgerFormats.h:72
ripple::ltACCOUNT_ROOT
@ ltACCOUNT_ROOT
Definition: LedgerFormats.h:53
ripple::keylet::depositPreauth
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
Definition: Indexes.cpp:283
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
Json::Value
Represents a JSON value.
Definition: json_value.h:145
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469