mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-21 22:30:57 +00:00
Merge branch 'develop' into ximinez/online-delete-gaps
This commit is contained in:
@@ -465,7 +465,7 @@ ValidVault::finalize(
|
||||
|
||||
if (afterVault.assetsAvailable < kZero)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: assets available must be positive";
|
||||
JLOG(j.fatal()) << "Invariant failed: assets available must not be negative";
|
||||
result = false;
|
||||
}
|
||||
|
||||
@@ -491,13 +491,13 @@ ValidVault::finalize(
|
||||
|
||||
if (afterVault.assetsTotal < kZero)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: assets outstanding must be positive";
|
||||
JLOG(j.fatal()) << "Invariant failed: assets outstanding must not be negative";
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (afterVault.assetsMaximum < kZero)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: assets maximum must be positive";
|
||||
JLOG(j.fatal()) << "Invariant failed: assets maximum must not be negative";
|
||||
result = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -813,7 +813,7 @@ LoanPay::doApply()
|
||||
XRPL_ASSERT_PARTS(
|
||||
vaultBalanceAfter >= beast::kZero && brokerBalanceAfter >= beast::kZero,
|
||||
"xrpl::LoanPay::doApply",
|
||||
"positive vault and broker balances");
|
||||
"non-negative vault and broker balances");
|
||||
XRPL_ASSERT_PARTS(
|
||||
vaultBalanceAfter >= vaultBalanceBefore,
|
||||
"xrpl::LoanPay::doApply",
|
||||
|
||||
@@ -3260,9 +3260,9 @@ class Invariants_test : public beast::unit_test::Suite
|
||||
"set must not change assets available",
|
||||
"set must not change shares outstanding",
|
||||
"set must not change vault balance",
|
||||
"assets available must be positive",
|
||||
"assets available must not be negative",
|
||||
"assets available must not be greater than assets outstanding",
|
||||
"assets outstanding must be positive"},
|
||||
"assets outstanding must not be negative"},
|
||||
[&](Account const& a1, Account const& a2, ApplyContext& ac) {
|
||||
auto const keylet = keylet::vault(a1.id(), ac.view().seq());
|
||||
auto sleVault = ac.view().peek(keylet);
|
||||
@@ -3424,7 +3424,7 @@ class Invariants_test : public beast::unit_test::Suite
|
||||
TxAccount::A2);
|
||||
|
||||
doInvariantCheck(
|
||||
{"assets maximum must be positive"},
|
||||
{"assets maximum must not be negative"},
|
||||
[&](Account const& a1, Account const& a2, ApplyContext& ac) {
|
||||
auto const keylet = keylet::vault(a1.id(), ac.view().seq());
|
||||
return kAdjust(ac.view(), keylet, kArgs(a2.id(), 0, [&](Adjustments& sample) {
|
||||
@@ -3612,7 +3612,7 @@ class Invariants_test : public beast::unit_test::Suite
|
||||
|
||||
doInvariantCheck(
|
||||
{
|
||||
"assets maximum must be positive",
|
||||
"assets maximum must not be negative",
|
||||
"create operation must not have updated a vault",
|
||||
},
|
||||
[&](Account const& a1, Account const& a2, ApplyContext& ac) {
|
||||
|
||||
@@ -320,6 +320,48 @@ public:
|
||||
BEAST_EXPECT(ret[jss::median] == "74");
|
||||
BEAST_EXPECT(ret[jss::time] == 946695000);
|
||||
}
|
||||
|
||||
// Duplicate oracle entries should be deduplicated.
|
||||
// Two separate oracles with different prices give size=2.
|
||||
// Listing the first oracle twice in the query must not
|
||||
// inflate the size to 3.
|
||||
{
|
||||
Env env(*this);
|
||||
auto const baseFee = static_cast<int>(env.current()->fees().base.drops());
|
||||
|
||||
Account const owner1{"owner1"};
|
||||
Account const owner2{"owner2"};
|
||||
env.fund(XRP(1'000), owner1);
|
||||
env.fund(XRP(1'000), owner2);
|
||||
Oracle const oracle1(
|
||||
env, {.owner = owner1, .series = {{"XRP", "USD", 740, 1}}, .fee = baseFee});
|
||||
Oracle const oracle2(
|
||||
env, {.owner = owner2, .series = {{"XRP", "USD", 840, 1}}, .fee = baseFee});
|
||||
|
||||
// Query with both oracles listed once
|
||||
OraclesData const single = {
|
||||
{owner1, oracle1.documentID()}, {owner2, oracle2.documentID()}};
|
||||
auto const retSingle = Oracle::aggregatePrice(env, "XRP", "USD", single);
|
||||
|
||||
// Query with oracle1 listed twice
|
||||
OraclesData const duplicated = {
|
||||
{owner1, oracle1.documentID()},
|
||||
{owner1, oracle1.documentID()},
|
||||
{owner2, oracle2.documentID()}};
|
||||
auto const retDup = Oracle::aggregatePrice(env, "XRP", "USD", duplicated);
|
||||
|
||||
// Results should be identical - duplicates must not be
|
||||
// double-counted
|
||||
BEAST_EXPECT(
|
||||
retSingle[jss::entire_set][jss::size] == retDup[jss::entire_set][jss::size]);
|
||||
BEAST_EXPECT(retDup[jss::entire_set][jss::size].asUInt() == 2);
|
||||
BEAST_EXPECT(
|
||||
retSingle[jss::entire_set][jss::mean] == retDup[jss::entire_set][jss::mean]);
|
||||
BEAST_EXPECT(
|
||||
retSingle[jss::entire_set][jss::standard_deviation] ==
|
||||
retDup[jss::entire_set][jss::standard_deviation]);
|
||||
BEAST_EXPECT(retSingle[jss::median] == retDup[jss::median]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -33,7 +33,9 @@
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -251,6 +253,8 @@ doGetAggregatePrice(rpc::JsonContext& context)
|
||||
// Collect the dataset into bimap keyed by lastUpdateTime and
|
||||
// STAmount (Number is int64 and price is uint64)
|
||||
Prices prices;
|
||||
// Track seen {account, documentID} pairs to skip duplicates
|
||||
std::set<std::pair<AccountID, std::uint32_t>> seen;
|
||||
for (auto const& oracle : params[jss::oracles])
|
||||
{
|
||||
if (!oracle.isMember(jss::oracle_document_id) || !oracle.isMember(jss::account))
|
||||
@@ -268,6 +272,10 @@ doGetAggregatePrice(rpc::JsonContext& context)
|
||||
return result;
|
||||
}
|
||||
|
||||
// Skip duplicate oracle entries
|
||||
if (!seen.emplace(*account, *documentID).second)
|
||||
continue;
|
||||
|
||||
auto const sle = ledger->read(keylet::oracle(*account, *documentID));
|
||||
iteratePriceData(context, sle, [&](STObject const& node) {
|
||||
auto const& series = node.getFieldArray(sfPriceDataSeries);
|
||||
|
||||
Reference in New Issue
Block a user