Add InvariantChecks for if OwnerCount < SponsoredOwnerCount

This commit is contained in:
tequ
2026-01-30 21:21:38 +09:00
parent 40cf5993c1
commit 8f8fc03800
3 changed files with 44 additions and 1 deletions

View File

@@ -101,7 +101,8 @@ class Invariants_test : public beast::unit_test::suite
if (messages.find(m) == std::string::npos)
{
// uncomment if you want to log the invariant failure
// std::cerr << " --> " << m << std::endl;
// std::cerr << " expected --> " << m << std::endl;
// std::cerr << " actual --> " << messages << std::endl;
fail();
}
}
@@ -3516,6 +3517,26 @@ class Invariants_test : public beast::unit_test::suite
});
}
{
auto const expect_message = "OwnerCount must be greater than or equal to SponsoredOwnerCount.";
doInvariantCheck({{expect_message}}, [&](Account const& A1, Account const& A2, ApplyContext& ac) {
auto const sle = ac.view().peek(keylet::account(A1.id()));
if (!sle)
return false;
sle->setFieldU32(sfOwnerCount, 0);
sle->setFieldU32(sfSponsoredOwnerCount, 1);
ac.view().update(sle);
auto const sle2 = ac.view().peek(keylet::account(A2.id()));
if (!sle2)
return false;
sle2->setFieldU32(sfSponsoringOwnerCount, 1);
ac.view().update(sle2);
return true;
});
}
{
auto const expect_message =
"Invariant failed: Net delta of SponsoringAccountCount does "

View File

@@ -3287,6 +3287,17 @@ SponsorshipOwnerCountsMatch::visitEntry(
return 0;
};
auto getOwnerCount = [](std::shared_ptr<SLE const> const& sle) -> std::uint32_t {
if (sle && sle->getType() == ltACCOUNT_ROOT)
return sle->getFieldU32(sfOwnerCount);
return 0;
};
auto getSponsoredOwnerCount = [](std::shared_ptr<SLE const> const& sle) -> std::uint32_t {
if (sle && sle->getType() == ltACCOUNT_ROOT)
return sle->getFieldU32(sfSponsoredOwnerCount);
return 0;
};
std::int64_t const beforeSponsored = getSponsored(before);
std::int64_t const afterSponsored = getSponsored(after);
std::int64_t const beforeSponsoring = getSponsoring(before);
@@ -3294,6 +3305,9 @@ SponsorshipOwnerCountsMatch::visitEntry(
deltaSponsoredOwnerCount_ += (afterSponsored - beforeSponsored);
deltaSponsoringOwnerCount_ += (afterSponsoring - beforeSponsoring);
if (getOwnerCount(after) < getSponsoredOwnerCount(after))
invalidOwnerCountLessThanSponsoredOwnerCount_ += 1;
}
bool
@@ -3306,6 +3320,12 @@ SponsorshipOwnerCountsMatch::finalize(STTx const&, TER const, XRPAmount const, R
return false;
}
if (invalidOwnerCountLessThanSponsoredOwnerCount_ > 0)
{
JLOG(j.fatal()) << "Invariant failed: OwnerCount must be greater than or equal to SponsoredOwnerCount.";
return false;
}
return true;
}

View File

@@ -401,11 +401,13 @@ public:
* The following check is made for every transaction:
* - The sum of all per-account deltas of `sfSponsoredOwnerCount` equals
* the sum of all per-account deltas of `sfSponsoringOwnerCount`.
* - Account OwnerCount must be greater than or equal to SponsoredOwnerCount.
*/
class SponsorshipOwnerCountsMatch
{
std::int64_t deltaSponsoredOwnerCount_ = 0;
std::int64_t deltaSponsoringOwnerCount_ = 0;
std::uint64_t invalidOwnerCountLessThanSponsoredOwnerCount_ = 0;
public:
void