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>
26#include <xrpl/json/json_value.h>
27#include <xrpl/protocol/ErrorCodes.h>
28#include <xrpl/protocol/jss.h>
30#include <boost/bimap.hpp>
31#include <boost/bimap/multiset_of.hpp>
35using namespace boost::bimaps;
38 multiset_of<std::uint32_t, std::greater<std::uint32_t>>,
39 multiset_of<STAmount>>;
75 if (prevChain == chain)
78 if (!oracle || f(*oracle) || isNew)
81 if (++history > maxHistory)
91 meta = ledger->txRead(prevTx).second;
96 if (node.getFieldU16(sfLedgerEntryType) != ltORACLE)
107 if (isNew && history == 1)
111 ? &
static_cast<const STObject&
>(node.peekAtField(sfNewFields))
113 node.peekAtField(sfFinalFields));
122 Prices::right_const_iterator
const& begin,
123 Prices::right_const_iterator
const& end)
129 begin, end, avg, [&](
STAmount const& acc,
auto const& it) {
130 return acc + it.first;
136 begin, end, sd, [&](
Number const& acc,
auto const& it) {
137 return acc + (it.first - avg) * (it.first - avg);
139 sd =
root2(sd / (size - 1));
141 return {avg, sd, size};
156 auto const& params(context.
params);
159 if (!params.isMember(jss::oracles))
161 if (!params[jss::oracles].isArray() || params[jss::oracles].size() == 0 ||
162 params[jss::oracles].size() > maxOracles)
168 if (!params.isMember(jss::base_asset))
171 if (!params.isMember(jss::quote_asset))
178 auto const& jv = params[field];
180 return jv.isUInt() || (jv.isInt() && jv.asInt() >= 0) ||
186 auto getField = [¶ms, &validUInt](
192 if (!validUInt(params, field))
194 return params[field].
asUInt();
206 if (params[field].asString().empty())
209 return params[field];
217 auto const trim = getField(jss::trim);
218 if (std::holds_alternative<error_code_i>(trim))
224 (std::get<std::uint32_t>(trim) == 0 ||
225 std::get<std::uint32_t>(trim) >
maxTrim))
231 auto const timeThreshold = getField(jss::time_threshold, 0);
232 if (std::holds_alternative<error_code_i>(timeThreshold))
238 auto const baseAsset = getCurrency(sfBaseAsset, jss::base_asset);
239 if (std::holds_alternative<error_code_i>(baseAsset))
244 auto const quoteAsset = getCurrency(sfQuoteAsset, jss::quote_asset);
245 if (std::holds_alternative<error_code_i>(quoteAsset))
254 for (
auto const& oracle : params[jss::oracles])
256 if (!oracle.isMember(jss::oracle_document_id) ||
257 !oracle.isMember(jss::account))
262 auto const documentID = validUInt(oracle, jss::oracle_document_id)
266 parseBase58<AccountID>(oracle[jss::account].asString());
267 if (!account || account->
isZero() || !documentID)
278 auto const sle = ledger->read(
keylet::oracle(*account, *documentID));
286 return o.getFieldCurrency(sfBaseAsset).getText() ==
287 std::get<Json::Value>(baseAsset) &&
288 o.getFieldCurrency(sfQuoteAsset).getText() ==
289 std::get<Json::Value>(quoteAsset) &&
290 o.isFieldPresent(sfAssetPrice);
292 iter != series.end())
294 auto const price = iter->getFieldU64(sfAssetPrice);
295 auto const scale = iter->isFieldPresent(sfScale)
296 ? -static_cast<int>(iter->getFieldU8(sfScale))
298 prices.insert(Prices::value_type(
299 node.getFieldU32(sfLastUpdateTime),
300 STAmount{noIssue(), price, scale}));
315 auto const latestTime = prices.left.begin()->first;
316 if (
auto const threshold = std::get<std::uint32_t>(timeThreshold))
321 auto const oldestTime = prices.left.rbegin()->first;
322 auto const upperBound =
323 latestTime > threshold ? (latestTime - threshold) : oldestTime;
324 if (upperBound > oldestTime)
326 prices.left.upper_bound(upperBound), prices.left.end());
339 result[jss::time] = latestTime;
342 auto const [avg, sd,
size] =
343 getStats(prices.right.begin(), prices.right.end());
344 result[jss::entire_set][jss::mean] = avg.getText();
345 result[jss::entire_set][jss::size] =
size;
346 result[jss::entire_set][jss::standard_deviation] =
to_string(sd);
348 auto itAdvance = [&](
auto it,
int distance) {
353 auto const median = [&prices, &itAdvance, &size_ =
size]() {
354 auto const middle = size_ / 2;
355 if ((size_ % 2) == 0)
357 static STAmount two{
noIssue(), 2, 0};
358 auto it = itAdvance(prices.right.begin(), middle - 1);
359 auto const& a1 = it->first;
360 auto const& a2 = (++it)->first;
363 return itAdvance(prices.right.begin(), middle)->first;
365 result[jss::median] = median.getText();
367 if (std::get<std::uint32_t>(trim) != 0)
369 auto const trimCount =
370 prices.size() * std::get<std::uint32_t>(trim) / 100;
373 itAdvance(prices.right.begin(), trimCount),
374 itAdvance(prices.right.end(), -trimCount));
375 result[jss::trimmed_set][jss::mean] = avg.getText();
376 result[jss::trimmed_set][jss::size] =
size;
377 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