20#include <xrpld/app/ledger/LedgerMaster.h>
21#include <xrpld/app/main/Application.h>
22#include <xrpld/ledger/ReadView.h>
23#include <xrpld/rpc/Context.h>
24#include <xrpld/rpc/detail/RPCHelpers.h>
25#include <xrpl/json/json_value.h>
26#include <xrpl/protocol/ErrorCodes.h>
27#include <xrpl/protocol/jss.h>
29#include <boost/bimap.hpp>
30#include <boost/bimap/multiset_of.hpp>
34using namespace boost::bimaps;
37 multiset_of<std::uint32_t, std::greater<std::uint32_t>>,
38 multiset_of<STAmount>>;
74 if (prevChain == chain)
77 if (!oracle || f(*oracle) || isNew)
80 if (++history > maxHistory)
90 meta = ledger->txRead(prevTx).second;
95 if (node.getFieldU16(sfLedgerEntryType) != ltORACLE)
106 if (isNew && history == 1)
110 ? &
static_cast<const STObject&
>(node.peekAtField(sfNewFields))
112 node.peekAtField(sfFinalFields));
121 Prices::right_const_iterator
const& begin,
122 Prices::right_const_iterator
const& end)
128 begin, end, avg, [&](
STAmount const& acc,
auto const& it) {
129 return acc + it.first;
135 begin, end, sd, [&](
Number const& acc,
auto const& it) {
136 return acc + (it.first - avg) * (it.first - avg);
138 sd =
root2(sd / (size - 1));
140 return {avg, sd, size};
155 auto const& params(context.
params);
158 if (!params.isMember(jss::oracles))
160 if (!params[jss::oracles].isArray() || params[jss::oracles].size() == 0 ||
161 params[jss::oracles].size() > maxOracles)
167 if (!params.isMember(jss::base_asset))
170 if (!params.isMember(jss::quote_asset))
177 auto const& jv = params[field];
179 return jv.isUInt() || (jv.isInt() && jv.asInt() >= 0) ||
185 auto getField = [¶ms, &validUInt](
191 if (!validUInt(params, field))
193 return params[field].
asUInt();
205 if (params[field].asString().empty())
208 return params[field];
216 auto const trim = getField(jss::trim);
217 if (std::holds_alternative<error_code_i>(trim))
223 (std::get<std::uint32_t>(trim) == 0 ||
224 std::get<std::uint32_t>(trim) >
maxTrim))
230 auto const timeThreshold = getField(jss::time_threshold, 0);
231 if (std::holds_alternative<error_code_i>(timeThreshold))
237 auto const baseAsset = getCurrency(sfBaseAsset, jss::base_asset);
238 if (std::holds_alternative<error_code_i>(baseAsset))
243 auto const quoteAsset = getCurrency(sfQuoteAsset, jss::quote_asset);
244 if (std::holds_alternative<error_code_i>(quoteAsset))
253 for (
auto const& oracle : params[jss::oracles])
255 if (!oracle.isMember(jss::oracle_document_id) ||
256 !oracle.isMember(jss::account))
261 auto const documentID = validUInt(oracle, jss::oracle_document_id)
265 parseBase58<AccountID>(oracle[jss::account].asString());
266 if (!account || account->
isZero() || !documentID)
277 auto const sle = ledger->read(
keylet::oracle(*account, *documentID));
285 return o.getFieldCurrency(sfBaseAsset).getText() ==
286 std::get<Json::Value>(baseAsset) &&
287 o.getFieldCurrency(sfQuoteAsset).getText() ==
288 std::get<Json::Value>(quoteAsset) &&
289 o.isFieldPresent(sfAssetPrice);
291 iter != series.end())
293 auto const price = iter->getFieldU64(sfAssetPrice);
294 auto const scale = iter->isFieldPresent(sfScale)
295 ? -static_cast<int>(iter->getFieldU8(sfScale))
297 prices.insert(Prices::value_type(
298 node.getFieldU32(sfLastUpdateTime),
299 STAmount{noIssue(), price, scale}));
314 auto const latestTime = prices.left.begin()->first;
315 if (
auto const threshold = std::get<std::uint32_t>(timeThreshold))
320 auto const oldestTime = prices.left.rbegin()->first;
321 auto const upperBound =
322 latestTime > threshold ? (latestTime - threshold) : oldestTime;
323 if (upperBound > oldestTime)
325 prices.left.upper_bound(upperBound), prices.left.end());
338 result[jss::time] = latestTime;
341 auto const [avg, sd,
size] =
342 getStats(prices.right.begin(), prices.right.end());
343 result[jss::entire_set][jss::mean] = avg.getText();
344 result[jss::entire_set][jss::size] =
size;
345 result[jss::entire_set][jss::standard_deviation] =
to_string(sd);
347 auto itAdvance = [&](
auto it,
int distance) {
352 auto const median = [&prices, &itAdvance, &size_ =
size]() {
353 auto const middle = size_ / 2;
354 if ((size_ % 2) == 0)
356 static STAmount two{
noIssue(), 2, 0};
357 auto it = itAdvance(prices.right.begin(), middle - 1);
358 auto const& a1 = it->first;
359 auto const& a2 = (++it)->first;
362 return itAdvance(prices.right.begin(), middle)->first;
364 result[jss::median] = median.getText();
366 if (std::get<std::uint32_t>(trim) != 0)
368 auto const trimCount =
369 prices.size() * std::get<std::uint32_t>(trim) / 100;
372 itAdvance(prices.right.begin(), trimCount),
373 itAdvance(prices.right.end(), -trimCount));
374 result[jss::trimmed_set][jss::mean] = avg.getText();
375 result[jss::trimmed_set][jss::size] =
size;
376 result[jss::trimmed_set][jss::standard_deviation] =
to_string(sd);
Lightweight wrapper to tag static string.
bool isMember(const char *key) const
Return true if the object has a member named key.
std::shared_ptr< Ledger const > getLedgerBySeq(std::uint32_t index)
const STArray & getFieldArray(SField const &field) const
std::uint32_t getFieldU32(SField const &field) const
bool isFieldPresent(SField const &field) const
uint256 getFieldH256(SField const &field) const
T make_optional(T... args)
bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
void inject_error(error_code_i code, JsonValue &json)
Add or update the json update to reflect the error code.
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)
Keylet oracle(AccountID const &account, std::uint32_t const &documentID) noexcept
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
STAmount divide(STAmount const &amount, Rate const &rate)
Json::Value doGetAggregatePrice(RPC::JsonContext &context)
oracles: array of {account, oracle_document_id} base_asset: is the asset to be priced quote_asset: is...
STCurrency currencyFromJson(SField const &name, Json::Value const &v)
std::size_t constexpr maxTrim
The maximum percentage of outliers to trim.
Issue const & noIssue()
Returns an asset specifier that represents no account and currency.
bimap< multiset_of< std::uint32_t, std::greater< std::uint32_t > >, multiset_of< STAmount > > Prices
static void iteratePriceData(RPC::JsonContext &context, std::shared_ptr< SLE const > const &sle, std::function< bool(STObject const &)> &&f)
Calls callback "f" on the ledger-object sle and up to three previous metadata objects.
std::string to_string(base_uint< Bits, Tag > const &a)
static std::tuple< STAmount, Number, std::uint16_t > getStats(Prices::right_const_iterator const &begin, Prices::right_const_iterator const &end)
LedgerMaster & ledgerMaster