rippled
Loading...
Searching...
No Matches
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 <xrpld/app/main/Application.h>
21#include <xrpld/app/misc/NetworkOPs.h>
22#include <xrpld/rpc/BookChanges.h>
23#include <xrpld/rpc/Context.h>
24#include <xrpld/rpc/detail/RPCHelpers.h>
25
26#include <xrpl/basics/Log.h>
27#include <xrpl/ledger/ReadView.h>
28#include <xrpl/protocol/ErrorCodes.h>
29#include <xrpl/protocol/RPCErr.h>
30#include <xrpl/protocol/UintTypes.h>
31#include <xrpl/protocol/jss.h>
32#include <xrpl/resource/Fees.h>
33
34namespace ripple {
35
38{
39 // VFALCO TODO Here is a terrible place for this kind of business
40 // logic. It needs to be moved elsewhere and documented,
41 // and encapsulated into a function.
42 if (context.app.getJobQueue().getJobCountGE(jtCLIENT) > 200)
43 return rpcError(rpcTOO_BUSY);
44
46 auto jvResult = RPC::lookupLedger(lpLedger, context);
47
48 if (!lpLedger)
49 return jvResult;
50
51 if (!context.params.isMember(jss::taker_pays))
52 return RPC::missing_field_error(jss::taker_pays);
53
54 if (!context.params.isMember(jss::taker_gets))
55 return RPC::missing_field_error(jss::taker_gets);
56
57 Json::Value const& taker_pays = context.params[jss::taker_pays];
58 Json::Value const& taker_gets = context.params[jss::taker_gets];
59
60 if (!taker_pays.isObjectOrNull())
61 return RPC::object_field_error(jss::taker_pays);
62
63 if (!taker_gets.isObjectOrNull())
64 return RPC::object_field_error(jss::taker_gets);
65
66 if (!taker_pays.isMember(jss::currency))
67 return RPC::missing_field_error("taker_pays.currency");
68
69 if (!taker_pays[jss::currency].isString())
70 return RPC::expected_field_error("taker_pays.currency", "string");
71
72 if (!taker_gets.isMember(jss::currency))
73 return RPC::missing_field_error("taker_gets.currency");
74
75 if (!taker_gets[jss::currency].isString())
76 return RPC::expected_field_error("taker_gets.currency", "string");
77
78 Currency pay_currency;
79
80 if (!to_currency(pay_currency, taker_pays[jss::currency].asString()))
81 {
82 JLOG(context.j.info()) << "Bad taker_pays currency.";
83 return RPC::make_error(
85 "Invalid field 'taker_pays.currency', bad currency.");
86 }
87
88 Currency get_currency;
89
90 if (!to_currency(get_currency, taker_gets[jss::currency].asString()))
91 {
92 JLOG(context.j.info()) << "Bad taker_gets currency.";
93 return RPC::make_error(
95 "Invalid field 'taker_gets.currency', bad currency.");
96 }
97
98 AccountID pay_issuer;
99
100 if (taker_pays.isMember(jss::issuer))
101 {
102 if (!taker_pays[jss::issuer].isString())
103 return RPC::expected_field_error("taker_pays.issuer", "string");
104
105 if (!to_issuer(pay_issuer, taker_pays[jss::issuer].asString()))
106 return RPC::make_error(
108 "Invalid field 'taker_pays.issuer', bad issuer.");
109
110 if (pay_issuer == noAccount())
111 return RPC::make_error(
113 "Invalid field 'taker_pays.issuer', bad issuer account one.");
114 }
115 else
116 {
117 pay_issuer = xrpAccount();
118 }
119
120 if (isXRP(pay_currency) && !isXRP(pay_issuer))
121 return RPC::make_error(
123 "Unneeded field 'taker_pays.issuer' for "
124 "XRP currency specification.");
125
126 if (!isXRP(pay_currency) && isXRP(pay_issuer))
127 return RPC::make_error(
129 "Invalid field 'taker_pays.issuer', expected non-XRP issuer.");
130
131 AccountID get_issuer;
132
133 if (taker_gets.isMember(jss::issuer))
134 {
135 if (!taker_gets[jss::issuer].isString())
136 return RPC::expected_field_error("taker_gets.issuer", "string");
137
138 if (!to_issuer(get_issuer, taker_gets[jss::issuer].asString()))
139 return RPC::make_error(
141 "Invalid field 'taker_gets.issuer', bad issuer.");
142
143 if (get_issuer == noAccount())
144 return RPC::make_error(
146 "Invalid field 'taker_gets.issuer', bad issuer account one.");
147 }
148 else
149 {
150 get_issuer = xrpAccount();
151 }
152
153 if (isXRP(get_currency) && !isXRP(get_issuer))
154 return RPC::make_error(
156 "Unneeded field 'taker_gets.issuer' for "
157 "XRP currency specification.");
158
159 if (!isXRP(get_currency) && isXRP(get_issuer))
160 return RPC::make_error(
162 "Invalid field 'taker_gets.issuer', expected non-XRP issuer.");
163
165 if (context.params.isMember(jss::taker))
166 {
167 if (!context.params[jss::taker].isString())
168 return RPC::expected_field_error(jss::taker, "string");
169
170 takerID = parseBase58<AccountID>(context.params[jss::taker].asString());
171 if (!takerID)
172 return RPC::invalid_field_error(jss::taker);
173 }
174
176 if (context.params.isMember(jss::domain))
177 {
178 uint256 num;
179 if (!context.params[jss::domain].isString() ||
180 !num.parseHex(context.params[jss::domain].asString()))
181 {
182 return RPC::make_error(
183 rpcDOMAIN_MALFORMED, "Unable to parse domain.");
184 }
185 else
186 {
187 domain = num;
188 }
189 }
190
191 if (pay_currency == get_currency && pay_issuer == get_issuer)
192 {
193 JLOG(context.j.info()) << "taker_gets same as taker_pays.";
195 }
196
197 unsigned int limit;
198 if (auto err = readLimitField(limit, RPC::Tuning::bookOffers, context))
199 return *err;
200
201 bool const bProof(context.params.isMember(jss::proof));
202
203 Json::Value const jvMarker(
204 context.params.isMember(jss::marker) ? context.params[jss::marker]
206
207 context.netOps.getBookPage(
208 lpLedger,
209 {{pay_currency, pay_issuer}, {get_currency, get_issuer}, domain},
210 takerID ? *takerID : beast::zero,
211 bProof,
212 limit,
213 jvMarker,
214 jvResult);
215
217
218 return jvResult;
219}
220
223{
225
226 Json::Value result = RPC::lookupLedger(ledger, context);
227 if (ledger == nullptr)
228 return result;
229
230 return RPC::computeBookChanges(ledger);
231}
232
233} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
bool isObjectOrNull() const
bool isString() const
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
Stream info() const
Definition Journal.h:334
virtual JobQueue & getJobQueue()=0
int getJobCountGE(JobType t) const
All waiting jobs at or greater than this priority.
Definition JobQueue.cpp:162
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
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:503
@ nullValue
'null' value
Definition json_value.h:38
static LimitRange constexpr bookOffers
Limits for the book_offers command.
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
Json::Value computeBookChanges(std::shared_ptr< L const > const &lpAccepted)
Definition BookChanges.h:47
Json::Value invalid_field_error(std::string const &name)
Definition ErrorCodes.h:325
Json::Value object_field_error(std::string const &name)
Definition ErrorCodes.h:301
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition ErrorCodes.h:349
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.
Json::Value missing_field_error(std::string const &name)
Definition ErrorCodes.h:283
Charge const feeMediumBurdenRPC
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
AccountID const & noAccount()
A placeholder for empty accounts.
bool isXRP(AccountID const &c)
Definition AccountID.h:90
AccountID const & xrpAccount()
Compute AccountID from public key.
bool to_issuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
@ rpcTOO_BUSY
Definition ErrorCodes.h:56
@ rpcBAD_MARKET
Definition ErrorCodes.h:97
@ rpcDOMAIN_MALFORMED
Definition ErrorCodes.h:158
@ rpcDST_ISR_MALFORMED
Definition ErrorCodes.h:108
@ rpcSRC_ISR_MALFORMED
Definition ErrorCodes.h:125
@ rpcDST_AMT_MALFORMED
Definition ErrorCodes.h:106
@ rpcSRC_CUR_MALFORMED
Definition ErrorCodes.h:124
Json::Value doBookChanges(RPC::JsonContext &context)
Json::Value rpcError(int iError)
Definition RPCErr.cpp:31
Json::Value doBookOffers(RPC::JsonContext &context)
@ jtCLIENT
Definition Job.h:45
bool to_currency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
Definition UintTypes.cpp:84
Resource::Charge & loadType
Definition Context.h:42
Application & app
Definition Context.h:41
beast::Journal const j
Definition Context.h:40
NetworkOPs & netOps
Definition Context.h:43