rippled
BookOffers.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/app/misc/NetworkOPs.h>
22 #include <ripple/basics/Log.h>
23 #include <ripple/ledger/ReadView.h>
24 #include <ripple/net/RPCErr.h>
25 #include <ripple/protocol/ErrorCodes.h>
26 #include <ripple/protocol/UintTypes.h>
27 #include <ripple/protocol/jss.h>
28 #include <ripple/resource/Fees.h>
29 #include <ripple/rpc/Context.h>
30 #include <ripple/rpc/impl/RPCHelpers.h>
31 
32 namespace ripple {
33 
36 {
37  // VFALCO TODO Here is a terrible place for this kind of business
38  // logic. It needs to be moved elsewhere and documented,
39  // and encapsulated into a function.
40  if (context.app.getJobQueue().getJobCountGE(jtCLIENT) > 200)
41  return rpcError(rpcTOO_BUSY);
42 
44  auto jvResult = RPC::lookupLedger(lpLedger, context);
45 
46  if (!lpLedger)
47  return jvResult;
48 
49  if (!context.params.isMember(jss::taker_pays))
50  return RPC::missing_field_error(jss::taker_pays);
51 
52  if (!context.params.isMember(jss::taker_gets))
53  return RPC::missing_field_error(jss::taker_gets);
54 
55  Json::Value const& taker_pays = context.params[jss::taker_pays];
56  Json::Value const& taker_gets = context.params[jss::taker_gets];
57 
58  if (!taker_pays.isObjectOrNull())
59  return RPC::object_field_error(jss::taker_pays);
60 
61  if (!taker_gets.isObjectOrNull())
62  return RPC::object_field_error(jss::taker_gets);
63 
64  if (!taker_pays.isMember(jss::currency))
65  return RPC::missing_field_error("taker_pays.currency");
66 
67  if (!taker_pays[jss::currency].isString())
68  return RPC::expected_field_error("taker_pays.currency", "string");
69 
70  if (!taker_gets.isMember(jss::currency))
71  return RPC::missing_field_error("taker_gets.currency");
72 
73  if (!taker_gets[jss::currency].isString())
74  return RPC::expected_field_error("taker_gets.currency", "string");
75 
76  Currency pay_currency;
77 
78  if (!to_currency(pay_currency, taker_pays[jss::currency].asString()))
79  {
80  JLOG(context.j.info()) << "Bad taker_pays currency.";
81  return RPC::make_error(
83  "Invalid field 'taker_pays.currency', bad currency.");
84  }
85 
86  Currency get_currency;
87 
88  if (!to_currency(get_currency, taker_gets[jss::currency].asString()))
89  {
90  JLOG(context.j.info()) << "Bad taker_gets currency.";
91  return RPC::make_error(
93  "Invalid field 'taker_gets.currency', bad currency.");
94  }
95 
96  AccountID pay_issuer;
97 
98  if (taker_pays.isMember(jss::issuer))
99  {
100  if (!taker_pays[jss::issuer].isString())
101  return RPC::expected_field_error("taker_pays.issuer", "string");
102 
103  if (!to_issuer(pay_issuer, taker_pays[jss::issuer].asString()))
104  return RPC::make_error(
106  "Invalid field 'taker_pays.issuer', bad issuer.");
107 
108  if (pay_issuer == noAccount())
109  return RPC::make_error(
111  "Invalid field 'taker_pays.issuer', bad issuer account one.");
112  }
113  else
114  {
115  pay_issuer = xrpAccount();
116  }
117 
118  if (isXRP(pay_currency) && !isXRP(pay_issuer))
119  return RPC::make_error(
121  "Unneeded field 'taker_pays.issuer' for "
122  "XRP currency specification.");
123 
124  if (!isXRP(pay_currency) && isXRP(pay_issuer))
125  return RPC::make_error(
127  "Invalid field 'taker_pays.issuer', expected non-XRP issuer.");
128 
129  AccountID get_issuer;
130 
131  if (taker_gets.isMember(jss::issuer))
132  {
133  if (!taker_gets[jss::issuer].isString())
134  return RPC::expected_field_error("taker_gets.issuer", "string");
135 
136  if (!to_issuer(get_issuer, taker_gets[jss::issuer].asString()))
137  return RPC::make_error(
139  "Invalid field 'taker_gets.issuer', bad issuer.");
140 
141  if (get_issuer == noAccount())
142  return RPC::make_error(
144  "Invalid field 'taker_gets.issuer', bad issuer account one.");
145  }
146  else
147  {
148  get_issuer = xrpAccount();
149  }
150 
151  if (isXRP(get_currency) && !isXRP(get_issuer))
152  return RPC::make_error(
154  "Unneeded field 'taker_gets.issuer' for "
155  "XRP currency specification.");
156 
157  if (!isXRP(get_currency) && isXRP(get_issuer))
158  return RPC::make_error(
160  "Invalid field 'taker_gets.issuer', expected non-XRP issuer.");
161 
162  boost::optional<AccountID> takerID;
163  if (context.params.isMember(jss::taker))
164  {
165  if (!context.params[jss::taker].isString())
166  return RPC::expected_field_error(jss::taker, "string");
167 
168  takerID = parseBase58<AccountID>(context.params[jss::taker].asString());
169  if (!takerID)
170  return RPC::invalid_field_error(jss::taker);
171  }
172 
173  if (pay_currency == get_currency && pay_issuer == get_issuer)
174  {
175  JLOG(context.j.info()) << "taker_gets same as taker_pays.";
177  }
178 
179  unsigned int limit;
180  if (auto err = readLimitField(limit, RPC::Tuning::bookOffers, context))
181  return *err;
182 
183  bool const bProof(context.params.isMember(jss::proof));
184 
185  Json::Value const jvMarker(
186  context.params.isMember(jss::marker) ? context.params[jss::marker]
188 
189  context.netOps.getBookPage(
190  lpLedger,
191  {{pay_currency, pay_issuer}, {get_currency, get_issuer}},
192  takerID ? *takerID : beast::zero,
193  bProof,
194  limit,
195  jvMarker,
196  jvResult);
197 
199 
200  return jvResult;
201 }
202 
203 } // namespace 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:83
ripple::RPC::JsonContext
Definition: Context.h:53
ripple::rpcDST_AMT_MALFORMED
@ rpcDST_AMT_MALFORMED
Definition: ErrorCodes.h:106
std::shared_ptr
STL class.
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1009
ripple::jtCLIENT
@ jtCLIENT
Definition: Job.h:48
ripple::Resource::feeMediumBurdenRPC
const Charge feeMediumBurdenRPC
ripple::RPC::Context::loadType
Resource::Charge & loadType
Definition: Context.h:43
ripple::rpcTOO_BUSY
@ rpcTOO_BUSY
Definition: ErrorCodes.h:56
ripple::RPC::Tuning::bookOffers
static constexpr LimitRange bookOffers
Limits for the book_offers command.
Definition: rpc/impl/Tuning.h:49
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::RPC::object_field_error
Json::Value object_field_error(std::string const &name)
Definition: ErrorCodes.h:254
ripple::RPC::expected_field_error
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:302
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:236
ripple::RPC::Context::j
const beast::Journal j
Definition: Context.h:41
ripple::base_uint< 160, detail::CurrencyTag >
ripple::NetworkOPs::getBookPage
virtual void getBookPage(std::shared_ptr< ReadView const > &lpLedger, Book const &book, AccountID const &uTakerID, bool const bProof, unsigned int iLimit, Json::Value const &jvMarker, Json::Value &jvResult)=0
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
ripple::rpcSRC_ISR_MALFORMED
@ rpcSRC_ISR_MALFORMED
Definition: ErrorCodes.h:125
ripple::xrpAccount
AccountID const & xrpAccount()
Compute AccountID from public key.
Definition: AccountID.cpp:90
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
beast::Journal::info
Stream info() const
Definition: Journal.h:321
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:89
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
ripple::rpcDST_ISR_MALFORMED
@ rpcDST_ISR_MALFORMED
Definition: ErrorCodes.h:108
ripple::doBookOffers
Json::Value doBookOffers(RPC::JsonContext &context)
Definition: BookOffers.cpp:35
ripple::rpcError
Json::Value rpcError(int iError, Json::Value jvResult)
Definition: RPCErr.cpp:29
ripple::RPC::Context::netOps
NetworkOPs & netOps
Definition: Context.h:44
ripple::JobQueue::getJobCountGE
int getJobCountGE(JobType t) const
All waiting jobs at or greater than this priority.
Definition: JobQueue.cpp:141
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
ripple::rpcBAD_MARKET
@ rpcBAD_MARKET
Definition: ErrorCodes.h:97
ripple::rpcSRC_CUR_MALFORMED
@ rpcSRC_CUR_MALFORMED
Definition: ErrorCodes.h:124
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
ripple::RPC::invalid_field_error
Json::Value invalid_field_error(std::string const &name)
Definition: ErrorCodes.h:278
Json::Value::isObjectOrNull
bool isObjectOrNull() const
Definition: json_value.cpp:1033
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:97
ripple::RPC::make_error
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
Definition: ErrorCodes.cpp:202
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::to_issuer
bool to_issuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
Definition: AccountID.cpp:104
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469