rippled
Loading...
Searching...
No Matches
AccountOffers.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/rpc/Context.h>
21#include <xrpld/rpc/detail/RPCHelpers.h>
22#include <xrpld/rpc/detail/Tuning.h>
23
24#include <xrpl/json/json_value.h>
25#include <xrpl/ledger/ReadView.h>
26#include <xrpl/ledger/View.h>
27#include <xrpl/protocol/ErrorCodes.h>
28#include <xrpl/protocol/RPCErr.h>
29#include <xrpl/protocol/jss.h>
30#include <xrpl/resource/Fees.h>
31
32namespace ripple {
33
34void
36{
37 STAmount dirRate =
38 amountFromQuality(getQuality(offer->getFieldH256(sfBookDirectory)));
39 Json::Value& obj(offers.append(Json::objectValue));
40 offer->getFieldAmount(sfTakerPays).setJson(obj[jss::taker_pays]);
41 offer->getFieldAmount(sfTakerGets).setJson(obj[jss::taker_gets]);
42 obj[jss::seq] = offer->getFieldU32(sfSequence);
43 obj[jss::flags] = offer->getFieldU32(sfFlags);
44 obj[jss::quality] = dirRate.getText();
45 if (offer->isFieldPresent(sfExpiration))
46 obj[jss::expiration] = offer->getFieldU32(sfExpiration);
47};
48
49// {
50// account: <account>
51// ledger_hash : <ledger>
52// ledger_index : <ledger_index>
53// limit: integer // optional
54// marker: opaque // optional, resume previous query
55// }
58{
59 auto const& params(context.params);
60 if (!params.isMember(jss::account))
61 return RPC::missing_field_error(jss::account);
62
63 if (!params[jss::account].isString())
64 return RPC::invalid_field_error(jss::account);
65
67 auto result = RPC::lookupLedger(ledger, context);
68 if (!ledger)
69 return result;
70
71 auto id = parseBase58<AccountID>(params[jss::account].asString());
72 if (!id)
73 {
75 return result;
76 }
77 auto const accountID{std::move(id.value())};
78
79 // Get info on account.
80 result[jss::account] = toBase58(accountID);
81
82 if (!ledger->exists(keylet::account(accountID)))
84
85 unsigned int limit;
86 if (auto err = readLimitField(limit, RPC::Tuning::accountOffers, context))
87 return *err;
88
89 if (limit == 0)
90 return RPC::invalid_field_error(jss::limit);
91
92 Json::Value& jsonOffers(result[jss::offers] = Json::arrayValue);
94 uint256 startAfter = beast::zero;
95 std::uint64_t startHint = 0;
96
97 if (params.isMember(jss::marker))
98 {
99 if (!params[jss::marker].isString())
100 return RPC::expected_field_error(jss::marker, "string");
101
102 // Marker is composed of a comma separated index and start hint. The
103 // former will be read as hex, and the latter using boost lexical cast.
104 std::stringstream marker(params[jss::marker].asString());
105 std::string value;
106 if (!std::getline(marker, value, ','))
107 return RPC::invalid_field_error(jss::marker);
108
109 if (!startAfter.parseHex(value))
110 return RPC::invalid_field_error(jss::marker);
111
112 if (!std::getline(marker, value, ','))
113 return RPC::invalid_field_error(jss::marker);
114
115 try
116 {
117 startHint = boost::lexical_cast<std::uint64_t>(value);
118 }
119 catch (boost::bad_lexical_cast&)
120 {
121 return RPC::invalid_field_error(jss::marker);
122 }
123
124 // We then must check if the object pointed to by the marker is actually
125 // owned by the account in the request.
126 auto const sle = ledger->read({ltANY, startAfter});
127
128 if (!sle)
130
131 if (!RPC::isRelatedToAccount(*ledger, sle, accountID))
133 }
134
135 auto count = 0;
136 std::optional<uint256> marker = {};
137 std::uint64_t nextHint = 0;
138 if (!forEachItemAfter(
139 *ledger,
140 accountID,
141 startAfter,
142 startHint,
143 limit + 1,
144 [&offers, &count, &marker, &limit, &nextHint, &accountID](
145 std::shared_ptr<SLE const> const& sle) {
146 if (!sle)
147 {
148 UNREACHABLE("ripple::doAccountOffers : null SLE");
149 return false;
150 }
151
152 if (++count == limit)
153 {
154 marker = sle->key();
155 nextHint = RPC::getStartHint(sle, accountID);
156 }
157
158 if (count <= limit && sle->getType() == ltOFFER)
159 {
160 offers.emplace_back(sle);
161 }
162
163 return true;
164 }))
165 {
167 }
168
169 // Both conditions need to be checked because marker is set on the limit-th
170 // item, but if there is no item on the limit + 1 iteration, then there is
171 // no need to return a marker.
172 if (count == limit + 1 && marker)
173 {
174 result[jss::limit] = limit;
175 result[jss::marker] =
176 to_string(*marker) + "," + std::to_string(nextHint);
177 }
178
179 for (auto const& offer : offers)
180 appendOfferJson(offer, jsonOffers);
181
183 return result;
184}
185
186} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
std::string getText() const override
Definition STAmount.cpp:706
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:503
T getline(T... args)
@ arrayValue
array value (ordered list)
Definition json_value.h:44
@ objectValue
object value (collection of name/value pairs).
Definition json_value.h:45
static LimitRange constexpr accountOffers
Limits for the account_offers command.
Json::Value invalid_field_error(std::string const &name)
Definition ErrorCodes.h:325
bool isRelatedToAccount(ReadView const &ledger, std::shared_ptr< SLE const > const &sle, AccountID const &accountID)
Tests if a SLE is owned by accountID.
void inject_error(error_code_i code, JsonValue &json)
Add or update the json update to reflect the error code.
Definition ErrorCodes.h:233
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.
std::uint64_t getStartHint(std::shared_ptr< SLE const > const &sle, AccountID const &accountID)
Gets the start hint for traversing account objects.
Json::Value missing_field_error(std::string const &name)
Definition ErrorCodes.h:283
Charge const feeMediumBurdenRPC
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:184
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
std::uint64_t getQuality(uint256 const &uBase)
Definition Indexes.cpp:149
@ rpcACT_NOT_FOUND
Definition ErrorCodes.h:70
@ rpcACT_MALFORMED
Definition ErrorCodes.h:90
@ rpcINVALID_PARAMS
Definition ErrorCodes.h:84
STAmount amountFromQuality(std::uint64_t rate)
Json::Value rpcError(int iError)
Definition RPCErr.cpp:31
bool forEachItemAfter(ReadView const &view, Keylet const &root, uint256 const &after, std::uint64_t const hint, unsigned int limit, std::function< bool(std::shared_ptr< SLE const > const &)> const &f)
Iterate all items after an item in the given directory.
Definition View.cpp:681
Json::Value doAccountOffers(RPC::JsonContext &context)
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:630
@ ltANY
A special type, matching any ledger entry type.
void appendOfferJson(std::shared_ptr< SLE const > const &offer, Json::Value &offers)
Resource::Charge & loadType
Definition Context.h:42
T to_string(T... args)