fix: No invariant verifying sfSponsor field on objects matches sponsoring/sponsored count deltas #6897

This commit is contained in:
tequ
2026-04-21 18:59:36 +09:00
parent b2b2babe1e
commit c072b125a0
2 changed files with 54 additions and 1 deletions

View File

@@ -21,6 +21,7 @@ class SponsorshipOwnerCountsMatch
{
std::int64_t deltaSponsoredOwnerCount_ = 0;
std::int64_t deltaSponsoringOwnerCount_ = 0;
std::int64_t deltaSponsoredObjectOwnerCount_ = 0;
std::uint64_t invalidOwnerCountLessThanSponsoredOwnerCount_ = 0;
public:

View File

@@ -1,13 +1,15 @@
#include <xrpl/tx/invariants/SponsorshipInvariant.h>
//
#include <xrpl/basics/Log.h>
#include <xrpl/protocol/STArray.h>
#include <xrpl/tx/transactors/oracle/OracleSet.h>
namespace xrpl {
// Add new sponsorship-related invariants implementations
void
SponsorshipOwnerCountsMatch::visitEntry(
bool,
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after)
{
@@ -33,14 +35,57 @@ SponsorshipOwnerCountsMatch::visitEntry(
return 0;
};
auto getSponsoredObjectOwnerCount =
[&](std::shared_ptr<SLE const> const& sle) -> std::uint32_t {
if (!sle)
return 0;
switch (sle->getType())
{
case ltACCOUNT_ROOT: {
return 0;
}
case ltRIPPLE_STATE: {
uint32_t ownerCount = 0;
if (sle->isFieldPresent(sfHighSponsor))
ownerCount++;
if (sle->isFieldPresent(sfLowSponsor))
ownerCount++;
return ownerCount;
}
case ltORACLE: {
if (!sle->isFieldPresent(sfSponsor))
return 0;
auto const priceDataSeries = sle->getFieldArray(sfPriceDataSeries);
return OracleSet::calculateOracleReserve(priceDataSeries.size());
}
case ltVAULT: {
if (!sle->isFieldPresent(sfSponsor))
return 0;
return 2;
}
default: {
if (sle->isFieldPresent(sfSponsor))
return 1;
return 0;
}
}
};
std::int64_t const beforeSponsored = getSponsored(before);
std::int64_t const afterSponsored = getSponsored(after);
std::int64_t const beforeSponsoring = getSponsoring(before);
std::int64_t const afterSponsoring = getSponsoring(after);
std::int64_t const beforeSponsoredObjectOwnerCount = getSponsoredObjectOwnerCount(before);
std::int64_t const afterSponsoredObjectOwnerCount =
isDelete ? 0 : getSponsoredObjectOwnerCount(after);
deltaSponsoredOwnerCount_ += (afterSponsored - beforeSponsored);
deltaSponsoringOwnerCount_ += (afterSponsoring - beforeSponsoring);
deltaSponsoredObjectOwnerCount_ +=
(afterSponsoredObjectOwnerCount - beforeSponsoredObjectOwnerCount);
if (getOwnerCount(after) < getSponsoredOwnerCount(after))
invalidOwnerCountLessThanSponsoredOwnerCount_ += 1;
}
@@ -60,6 +105,13 @@ SponsorshipOwnerCountsMatch::finalize(
return false;
}
if (deltaSponsoredObjectOwnerCount_ != deltaSponsoredOwnerCount_)
{
JLOG(j.fatal()) << "Invariant failed: SponsoredObjectOwnerCount does not "
"equal SponsoredOwnerCount delta.";
return false;
}
if (invalidOwnerCountLessThanSponsoredOwnerCount_ > 0)
{
JLOG(j.fatal())