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/BookChanges.h>
30 #include <ripple/rpc/Context.h>
31 #include <ripple/rpc/impl/RPCHelpers.h>
32 
33 namespace ripple {
34 
37 {
38  // VFALCO TODO Here is a terrible place for this kind of business
39  // logic. It needs to be moved elsewhere and documented,
40  // and encapsulated into a function.
41  if (context.app.getJobQueue().getJobCountGE(jtCLIENT) > 200)
42  return rpcError(rpcTOO_BUSY);
43 
45  auto jvResult = RPC::lookupLedger(lpLedger, context);
46 
47  if (!lpLedger)
48  return jvResult;
49 
50  if (!context.params.isMember(jss::taker_pays))
51  return RPC::missing_field_error(jss::taker_pays);
52 
53  if (!context.params.isMember(jss::taker_gets))
54  return RPC::missing_field_error(jss::taker_gets);
55 
56  Json::Value const& taker_pays = context.params[jss::taker_pays];
57  Json::Value const& taker_gets = context.params[jss::taker_gets];
58 
59  if (!taker_pays.isObjectOrNull())
60  return RPC::object_field_error(jss::taker_pays);
61 
62  if (!taker_gets.isObjectOrNull())
63  return RPC::object_field_error(jss::taker_gets);
64 
65  if (!taker_pays.isMember(jss::currency))
66  return RPC::missing_field_error("taker_pays.currency");
67 
68  if (!taker_pays[jss::currency].isString())
69  return RPC::expected_field_error("taker_pays.currency", "string");
70 
71  if (!taker_gets.isMember(jss::currency))
72  return RPC::missing_field_error("taker_gets.currency");
73 
74  if (!taker_gets[jss::currency].isString())
75  return RPC::expected_field_error("taker_gets.currency", "string");
76 
77  Currency pay_currency;
78 
79  if (!to_currency(pay_currency, taker_pays[jss::currency].asString()))
80  {
81  JLOG(context.j.info()) << "Bad taker_pays currency.";
82  return RPC::make_error(
84  "Invalid field 'taker_pays.currency', bad currency.");
85  }
86 
87  Currency get_currency;
88 
89  if (!to_currency(get_currency, taker_gets[jss::currency].asString()))
90  {
91  JLOG(context.j.info()) << "Bad taker_gets currency.";
92  return RPC::make_error(
94  "Invalid field 'taker_gets.currency', bad currency.");
95  }
96 
97  AccountID pay_issuer;
98 
99  if (taker_pays.isMember(jss::issuer))
100  {
101  if (!taker_pays[jss::issuer].isString())
102  return RPC::expected_field_error("taker_pays.issuer", "string");
103 
104  if (!to_issuer(pay_issuer, taker_pays[jss::issuer].asString()))
105  return RPC::make_error(
107  "Invalid field 'taker_pays.issuer', bad issuer.");
108 
109  if (pay_issuer == noAccount())
110  return RPC::make_error(
112  "Invalid field 'taker_pays.issuer', bad issuer account one.");
113  }
114  else
115  {
116  pay_issuer = xrpAccount();
117  }
118 
119  if (isXRP(pay_currency) && !isXRP(pay_issuer))
120  return RPC::make_error(
122  "Unneeded field 'taker_pays.issuer' for "
123  "XRP currency specification.");
124 
125  if (!isXRP(pay_currency) && isXRP(pay_issuer))
126  return RPC::make_error(
128  "Invalid field 'taker_pays.issuer', expected non-XRP issuer.");
129 
130  AccountID get_issuer;
131 
132  if (taker_gets.isMember(jss::issuer))
133  {
134  if (!taker_gets[jss::issuer].isString())
135  return RPC::expected_field_error("taker_gets.issuer", "string");
136 
137  if (!to_issuer(get_issuer, taker_gets[jss::issuer].asString()))
138  return RPC::make_error(
140  "Invalid field 'taker_gets.issuer', bad issuer.");
141 
142  if (get_issuer == noAccount())
143  return RPC::make_error(
145  "Invalid field 'taker_gets.issuer', bad issuer account one.");
146  }
147  else
148  {
149  get_issuer = xrpAccount();
150  }
151 
152  if (isXRP(get_currency) && !isXRP(get_issuer))
153  return RPC::make_error(
155  "Unneeded field 'taker_gets.issuer' for "
156  "XRP currency specification.");
157 
158  if (!isXRP(get_currency) && isXRP(get_issuer))
159  return RPC::make_error(
161  "Invalid field 'taker_gets.issuer', expected non-XRP issuer.");
162 
163  std::optional<AccountID> takerID;
164  if (context.params.isMember(jss::taker))
165  {
166  if (!context.params[jss::taker].isString())
167  return RPC::expected_field_error(jss::taker, "string");
168 
169  takerID = parseBase58<AccountID>(context.params[jss::taker].asString());
170  if (!takerID)
171  return RPC::invalid_field_error(jss::taker);
172  }
173 
174  if (pay_currency == get_currency && pay_issuer == get_issuer)
175  {
176  JLOG(context.j.info()) << "taker_gets same as taker_pays.";
178  }
179 
180  unsigned int limit;
181  if (auto err = readLimitField(limit, RPC::Tuning::bookOffers, context))
182  return *err;
183 
184  bool const bProof(context.params.isMember(jss::proof));
185 
186  Json::Value const jvMarker(
187  context.params.isMember(jss::marker) ? context.params[jss::marker]
189 
190  context.netOps.getBookPage(
191  lpLedger,
192  {{pay_currency, pay_issuer}, {get_currency, get_issuer}},
193  takerID ? *takerID : beast::zero,
194  bProof,
195  limit,
196  jvMarker,
197  jvResult);
198 
200 
201  return jvResult;
202 }
203 
206 {
207  auto res = RPC::getLedgerByContext(context);
208 
209  if (std::holds_alternative<Json::Value>(res))
210  return std::get<Json::Value>(res);
211 
213  std::get<std::shared_ptr<Ledger const>>(res));
214 }
215 
216 } // 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:80
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::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:29
ripple::jtCLIENT
@ jtCLIENT
Definition: Job.h:45
ripple::Resource::feeMediumBurdenRPC
const Charge feeMediumBurdenRPC
ripple::RPC::Context::loadType
Resource::Charge & loadType
Definition: Context.h:43
ripple::RPC::computeBookChanges
Json::Value computeBookChanges(std::shared_ptr< L const > const &lpAccepted)
Definition: BookChanges.h:38
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::getLedgerByContext
std::variant< std::shared_ptr< Ledger const >, Json::Value > getLedgerByContext(RPC::JsonContext &context)
Return a ledger based on ledger_hash or ledger_index, or an RPC error.
Definition: RPCHelpers.cpp:1054
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:675
ripple::RPC::object_field_error
Json::Value object_field_error(std::string const &name)
Definition: ErrorCodes.h:280
ripple::RPC::expected_field_error
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:328
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:262
ripple::RPC::Context::j
const beast::Journal j
Definition: Context.h:41
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:82
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:168
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:36
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:148
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
std::optional
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:304
Json::Value::isObjectOrNull
bool isObjectOrNull() const
Definition: json_value.cpp:1033
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:175
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:178
ripple::doBookChanges
Json::Value doBookChanges(RPC::JsonContext &context)
Definition: BookOffers.cpp:205
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:182
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469