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/strHex.h>
22 #include <ripple/basics/StringUtilities.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 // }
39 {
41  auto jvResult = RPC::lookupLedger (lpLedger, context);
42 
43  if (!lpLedger)
44  return jvResult;
45 
46  uint256 uNodeIndex;
47  bool bNodeBinary = false;
48  LedgerEntryType expectedType = ltANY;
49 
50  if (context.params.isMember (jss::index))
51  {
52  uNodeIndex.SetHex (context.params[jss::index].asString());
53  }
54  else if (context.params.isMember (jss::account_root))
55  {
56  expectedType = ltACCOUNT_ROOT;
57  auto const account = parseBase58<AccountID>(
58  context.params[jss::account_root].asString());
59  if (! account || account->isZero())
60  jvResult[jss::error] = "malformedAddress";
61  else
62  uNodeIndex = keylet::account(*account).key;
63  }
64  else if (context.params.isMember (jss::check))
65  {
66  expectedType = ltCHECK;
67  uNodeIndex.SetHex (context.params[jss::check].asString());
68  }
69  else if (context.params.isMember (jss::deposit_preauth))
70  {
71  expectedType = ltDEPOSIT_PREAUTH;
72 
73  if (!context.params[jss::deposit_preauth].isObject())
74  {
75  if (! context.params[jss::deposit_preauth].isString() ||
76  ! uNodeIndex.SetHex (
77  context.params[jss::deposit_preauth].asString()))
78  {
79  uNodeIndex = beast::zero;
80  jvResult[jss::error] = "malformedRequest";
81  }
82  }
83  else if (!context.params[jss::deposit_preauth].isMember (jss::owner)
84  || !context.params[jss::deposit_preauth][jss::owner].isString()
85  || !context.params[jss::deposit_preauth].isMember (jss::authorized)
86  || !context.params[jss::deposit_preauth][jss::authorized].isString())
87  {
88  jvResult[jss::error] = "malformedRequest";
89  }
90  else
91  {
92  auto const owner = parseBase58<AccountID>(context.params[
93  jss::deposit_preauth][jss::owner].asString());
94 
95  auto const authorized = parseBase58<AccountID>(context.params[
96  jss::deposit_preauth][jss::authorized].asString());
97 
98  if (! owner)
99  jvResult[jss::error] = "malformedOwner";
100  else if (! authorized)
101  jvResult[jss::error] = "malformedAuthorized";
102  else
103  uNodeIndex = keylet::depositPreauth (*owner, *authorized).key;
104  }
105  }
106  else if (context.params.isMember (jss::directory))
107  {
108  expectedType = ltDIR_NODE;
109  if (context.params[jss::directory].isNull())
110  {
111  jvResult[jss::error] = "malformedRequest";
112  }
113  else if (!context.params[jss::directory].isObject())
114  {
115  uNodeIndex.SetHex (context.params[jss::directory].asString ());
116  }
117  else if (context.params[jss::directory].isMember (jss::sub_index)
118  && !context.params[jss::directory][jss::sub_index].isIntegral ())
119  {
120  jvResult[jss::error] = "malformedRequest";
121  }
122  else
123  {
124  std::uint64_t uSubIndex
125  = context.params[jss::directory].isMember (jss::sub_index)
126  ? context.params[jss::directory][jss::sub_index].asUInt () : 0;
127 
128  if (context.params[jss::directory].isMember (jss::dir_root))
129  {
130  if (context.params[jss::directory].isMember (jss::owner))
131  {
132  // May not specify both dir_root and owner.
133  jvResult[jss::error] = "malformedRequest";
134  }
135  else
136  {
137  uint256 uDirRoot;
138  uDirRoot.SetHex (
139  context.params[jss::directory][jss::dir_root].asString());
140 
141  uNodeIndex = getDirNodeIndex (uDirRoot, uSubIndex);
142  }
143  }
144  else if (context.params[jss::directory].isMember (jss::owner))
145  {
146  auto const ownerID = parseBase58<AccountID>(
147  context.params[jss::directory][jss::owner].asString());
148 
149  if (! ownerID)
150  {
151  jvResult[jss::error] = "malformedAddress";
152  }
153  else
154  {
155  uint256 uDirRoot = getOwnerDirIndex (*ownerID);
156  uNodeIndex = getDirNodeIndex (uDirRoot, uSubIndex);
157  }
158  }
159  else
160  {
161  jvResult[jss::error] = "malformedRequest";
162  }
163  }
164  }
165  else if (context.params.isMember (jss::escrow))
166  {
167  expectedType = ltESCROW;
168  if (!context.params[jss::escrow].isObject ())
169  {
170  uNodeIndex.SetHex (context.params[jss::escrow].asString ());
171  }
172  else if (!context.params[jss::escrow].isMember (jss::owner)
173  || !context.params[jss::escrow].isMember (jss::seq)
174  || !context.params[jss::escrow][jss::seq].isIntegral ())
175  {
176  jvResult[jss::error] = "malformedRequest";
177  }
178  else
179  {
180  auto const id = parseBase58<AccountID>(
181  context.params[jss::escrow][jss::owner].asString());
182  if (! id)
183  jvResult[jss::error] = "malformedOwner";
184  else
185  uNodeIndex = keylet::escrow (*id,
186  context.params[jss::escrow][jss::seq].asUInt()).key;
187  }
188  }
189  else if (context.params.isMember (jss::offer))
190  {
191  expectedType = ltOFFER;
192  if (!context.params[jss::offer].isObject())
193  {
194  uNodeIndex.SetHex (context.params[jss::offer].asString ());
195  }
196  else if (!context.params[jss::offer].isMember (jss::account)
197  || !context.params[jss::offer].isMember (jss::seq)
198  || !context.params[jss::offer][jss::seq].isIntegral ())
199  {
200  jvResult[jss::error] = "malformedRequest";
201  }
202  else
203  {
204  auto const id = parseBase58<AccountID>(
205  context.params[jss::offer][jss::account].asString());
206  if (! id)
207  jvResult[jss::error] = "malformedAddress";
208  else
209  uNodeIndex = getOfferIndex (*id,
210  context.params[jss::offer][jss::seq].asUInt ());
211  }
212  }
213  else if (context.params.isMember (jss::payment_channel))
214  {
215  expectedType = ltPAYCHAN;
216  uNodeIndex.SetHex (context.params[jss::payment_channel].asString ());
217  }
218  else if (context.params.isMember (jss::ripple_state))
219  {
220  expectedType = ltRIPPLE_STATE;
221  Currency uCurrency;
222  Json::Value jvRippleState = context.params[jss::ripple_state];
223 
224  if (!jvRippleState.isObject()
225  || !jvRippleState.isMember (jss::currency)
226  || !jvRippleState.isMember (jss::accounts)
227  || !jvRippleState[jss::accounts].isArray()
228  || 2 != jvRippleState[jss::accounts].size ()
229  || !jvRippleState[jss::accounts][0u].isString ()
230  || !jvRippleState[jss::accounts][1u].isString ()
231  || (jvRippleState[jss::accounts][0u].asString ()
232  == jvRippleState[jss::accounts][1u].asString ())
233  )
234  {
235  jvResult[jss::error] = "malformedRequest";
236  }
237  else
238  {
239  auto const id1 = parseBase58<AccountID>(
240  jvRippleState[jss::accounts][0u].asString());
241  auto const id2 = parseBase58<AccountID>(
242  jvRippleState[jss::accounts][1u].asString());
243  if (! id1 || ! id2)
244  {
245  jvResult[jss::error] = "malformedAddress";
246  }
247  else if (!to_currency (uCurrency,
248  jvRippleState[jss::currency].asString()))
249  {
250  jvResult[jss::error] = "malformedCurrency";
251  }
252  else
253  {
254  uNodeIndex = getRippleStateIndex(
255  *id1, *id2, uCurrency);
256  }
257  }
258  }
259  else
260  {
261  jvResult[jss::error] = "unknownOption";
262  }
263 
264  if (uNodeIndex.isNonZero ())
265  {
266  auto const sleNode = lpLedger->read(keylet::unchecked(uNodeIndex));
267  if (context.params.isMember(jss::binary))
268  bNodeBinary = context.params[jss::binary].asBool();
269 
270  if (!sleNode)
271  {
272  // Not found.
273  jvResult[jss::error] = "entryNotFound";
274  }
275  else if ((expectedType != ltANY) &&
276  (expectedType != sleNode->getType()))
277  {
278  jvResult[jss::error] = "malformedRequest";
279  }
280  else if (bNodeBinary)
281  {
282  Serializer s;
283 
284  sleNode->add (s);
285 
286  jvResult[jss::node_binary] = strHex (s.peekData ());
287  jvResult[jss::index] = to_string (uNodeIndex);
288  }
289  else
290  {
291  jvResult[jss::node] = sleNode->getJson (JsonOptions::none);
292  jvResult[jss::index] = to_string (uNodeIndex);
293  }
294  }
295 
296  return jvResult;
297 }
298 
299 } // ripple
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:67
ripple::RPC::JsonContext
Definition: Context.h:52
ripple::doLedgerEntry
Json::Value doLedgerEntry(RPC::JsonContext &)
Definition: LedgerEntry.cpp:38
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1069
std::shared_ptr
STL class.
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1049
ripple::base_uint::isNonZero
bool isNonZero() const
Definition: base_uint.h:430
ripple::ltESCROW
@ ltESCROW
Definition: LedgerFormats.h:81
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:42
ripple::getOfferIndex
uint256 getOfferIndex(AccountID const &account, std::uint32_t uSequence)
Definition: Indexes.cpp:80
Json::Value::isNull
bool isNull() const
isNull() tests to see if this field is null.
Definition: json_value.cpp:998
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
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:484
ripple::ltCHECK
@ ltCHECK
Definition: LedgerFormats.h:86
ripple::keylet::depositPreauth
static const depositPreauth_t depositPreauth
Definition: Indexes.h:269
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:626
ripple::Keylet::key
uint256 key
Definition: Keylet.h:41
ripple::base_uint< 256 >
ripple::getDirNodeIndex
uint256 getDirNodeIndex(uint256 const &uDirRoot, const std::uint64_t uNodeIndex)
Definition: Indexes.cpp:98
ripple::base_uint::isZero
bool isZero() const
Definition: base_uint.h:429
ripple::authorized
static bool authorized(Port const &port, std::map< std::string, std::string > const &h)
Definition: ServerHandlerImp.cpp:90
ripple::keylet::account
static const account_t account
Definition: Indexes.h:116
ripple::JsonOptions::none
@ none
ripple::getRippleStateIndex
uint256 getRippleStateIndex(AccountID const &a, AccountID const &b, Currency const &currency)
Definition: Indexes.cpp:151
ripple::keylet::escrow
Keylet escrow(AccountID const &source, std::uint32_t seq)
An escrow entry.
Definition: Indexes.cpp:339
ripple::getOwnerDirIndex
uint256 getOwnerDirIndex(AccountID const &account)
Definition: Indexes.cpp:89
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:362
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:720
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:961
std::uint64_t
ripple::ltDEPOSIT_PREAUTH
@ ltDEPOSIT_PREAUTH
Definition: LedgerFormats.h:88
ripple::ReadView::read
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
ripple::keylet::unchecked
Keylet unchecked(uint256 const &key)
Any ledger entry.
Definition: Indexes.cpp:313
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1056
ripple::Serializer
Definition: Serializer.h:43
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:67
ripple::LedgerEntryType
LedgerEntryType
Ledger entry types.
Definition: LedgerFormats.h:36
ripple::Serializer::peekData
Blob const & peekData() const
Definition: Serializer.h:173
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:555
Json::Value::isIntegral
bool isIntegral() const
Definition: json_value.cpp:1026
ripple::ltPAYCHAN
@ ltPAYCHAN
Definition: LedgerFormats.h:84
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:70
ripple::ltDIR_NODE
@ ltDIR_NODE
Directory node.
Definition: LedgerFormats.h:65
ripple::ltOFFER
@ ltOFFER
Definition: LedgerFormats.h:73
ripple::ltACCOUNT_ROOT
@ ltACCOUNT_ROOT
Definition: LedgerFormats.h:54
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:63
Json::Value
Represents a JSON value.
Definition: json_value.h:141
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:482