Merge branch 'develop' into sponsor

This commit is contained in:
tequ
2025-09-20 23:08:53 +09:00
264 changed files with 7275 additions and 3011 deletions

View File

@@ -31,6 +31,7 @@
#include <boost/algorithm/string/predicate.hpp>
namespace ripple {
namespace test {
class Invariants_test : public beast::unit_test::suite
{
@@ -112,18 +113,13 @@ class Invariants_test : public beast::unit_test::suite
{
terActual = ac.checkInvariants(terActual, fee);
BEAST_EXPECT(terExpect == terActual);
if (terExpect != terActual)
{
printf("terActual: %s\n", transHuman(terActual).c_str());
printf("terExpect: %s\n", transHuman(terExpect).c_str());
}
auto const messages = sink.messages().str();
BEAST_EXPECT(
sink.messages().str().starts_with("Invariant failed:") ||
sink.messages().str().starts_with(
"Transaction caused an exception"));
messages.starts_with("Invariant failed:") ||
messages.starts_with("Transaction caused an exception"));
for (auto const& m : expect_logs)
{
if (sink.messages().str().find(m) == std::string::npos)
if (messages.find(m) == std::string::npos)
{
// uncomment if you want to log the invariant failure
// message log << " --> " << m << std::endl;
@@ -1440,6 +1436,127 @@ class Invariants_test : public beast::unit_test::suite
{tecINVARIANT_FAILED, tecINVARIANT_FAILED});
}
void
testValidPseudoAccounts()
{
testcase << "valid pseudo accounts";
using namespace jtx;
AccountID pseudoAccountID;
Preclose createPseudo =
[&, this](Account const& a, Account const& b, Env& env) {
PrettyAsset const xrpAsset{xrpIssue(), 1'000'000};
// Create vault
Vault vault{env};
auto [tx, vKeylet] =
vault.create({.owner = a, .asset = xrpAsset});
env(tx);
env.close();
if (auto const vSle = env.le(vKeylet); BEAST_EXPECT(vSle))
{
pseudoAccountID = vSle->at(sfAccount);
}
return BEAST_EXPECT(env.le(keylet::account(pseudoAccountID)));
};
/* Cases to check
"pseudo-account has 0 pseudo-account fields set"
"pseudo-account has 2 pseudo-account fields set"
"pseudo-account sequence changed"
"pseudo-account flags are not set"
"pseudo-account has a regular key"
*/
struct Mod
{
std::string expectedFailure;
std::function<void(SLE::pointer&)> func;
};
auto const mods = std::to_array<Mod>({
{
"pseudo-account has 0 pseudo-account fields set",
[this](SLE::pointer& sle) {
BEAST_EXPECT(sle->at(~sfVaultID));
sle->at(~sfVaultID) = std::nullopt;
},
},
{
"pseudo-account sequence changed",
[](SLE::pointer& sle) { sle->at(sfSequence) = 12345; },
},
{
"pseudo-account flags are not set",
[](SLE::pointer& sle) { sle->at(sfFlags) = lsfNoFreeze; },
},
{
"pseudo-account has a regular key",
[](SLE::pointer& sle) {
sle->at(sfRegularKey) = Account("regular").id();
},
},
});
for (auto const& mod : mods)
{
doInvariantCheck(
{{mod.expectedFailure}},
[&](Account const& A1, Account const&, ApplyContext& ac) {
auto sle = ac.view().peek(keylet::account(pseudoAccountID));
if (!sle)
return false;
mod.func(sle);
ac.view().update(sle);
return true;
},
XRPAmount{},
STTx{ttACCOUNT_SET, [](STObject& tx) {}},
{tecINVARIANT_FAILED, tefINVARIANT_FAILED},
createPseudo);
}
for (auto const pField : getPseudoAccountFields())
{
// createPseudo creates a vault, so sfVaultID will be set, and
// setting it again will not cause an error
if (pField == &sfVaultID)
continue;
doInvariantCheck(
{{"pseudo-account has 2 pseudo-account fields set"}},
[&](Account const& A1, Account const&, ApplyContext& ac) {
auto sle = ac.view().peek(keylet::account(pseudoAccountID));
if (!sle)
return false;
auto const vaultID = ~sle->at(~sfVaultID);
BEAST_EXPECT(vaultID && !sle->isFieldPresent(*pField));
sle->setFieldH256(*pField, *vaultID);
ac.view().update(sle);
return true;
},
XRPAmount{},
STTx{ttACCOUNT_SET, [](STObject& tx) {}},
{tecINVARIANT_FAILED, tefINVARIANT_FAILED},
createPseudo);
}
// Take one of the regular accounts and set the sequence to 0, which
// will make it look like a pseudo-account
doInvariantCheck(
{{"pseudo-account has 0 pseudo-account fields set"},
{"pseudo-account sequence changed"},
{"pseudo-account flags are not set"}},
[&](Account const& A1, Account const&, ApplyContext& ac) {
auto sle = ac.view().peek(keylet::account(A1.id()));
if (!sle)
return false;
sle->at(sfSequence) = 0;
ac.view().update(sle);
return true;
});
}
void
testPermissionedDEX()
{
@@ -1690,6 +1807,7 @@ public:
testValidNewAccountRoot();
testNFTokenPageInvariants();
testPermissionedDomainInvariants();
testValidPseudoAccounts();
testPermissionedDEX();
testSponsorship();
}
@@ -1697,4 +1815,5 @@ public:
BEAST_DEFINE_TESTSUITE(Invariants, app, ripple);
} // namespace test
} // namespace ripple