diff --git a/include/xrpl/tx/invariants/SponsorshipInvariant.h b/include/xrpl/tx/invariants/SponsorshipInvariant.h index fc6f87f3f0..15088eda00 100644 --- a/include/xrpl/tx/invariants/SponsorshipInvariant.h +++ b/include/xrpl/tx/invariants/SponsorshipInvariant.h @@ -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: diff --git a/src/libxrpl/tx/invariants/SponsorshipInvariant.cpp b/src/libxrpl/tx/invariants/SponsorshipInvariant.cpp index 72fdb5c842..c429a00455 100644 --- a/src/libxrpl/tx/invariants/SponsorshipInvariant.cpp +++ b/src/libxrpl/tx/invariants/SponsorshipInvariant.cpp @@ -1,13 +1,15 @@ #include // #include +#include +#include namespace xrpl { // Add new sponsorship-related invariants implementations void SponsorshipOwnerCountsMatch::visitEntry( - bool, + bool isDelete, std::shared_ptr const& before, std::shared_ptr const& after) { @@ -33,14 +35,57 @@ SponsorshipOwnerCountsMatch::visitEntry( return 0; }; + auto getSponsoredObjectOwnerCount = + [&](std::shared_ptr 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())