Compare commits

...

5 Commits

Author SHA1 Message Date
Olek
8449c6c365 Fix: nullptr resolving without db config (#6029)
If the config disables SQL db usage, such as a validator:

```
[ledger_tx_tables]
use_tx_tables = 0
```

then the pointer to DB engine is null, but it was still resolved during startup. Although it didn't crash in Release mode, possibly due to the compiler optimizing it away, it did crash in Debug mode. This change explicitly checks for the validity of the pointer and generates a runtime error if not set.
2025-11-21 22:20:45 +00:00
Vito Tumas
58e03190ac docs: Improve VaultWithdraw documentation (#6068) 2025-11-21 16:59:12 -05:00
Jingchen
fb74dc28e1 chore: Clean up comment in NetworkOps_test.cpp (#6066)
This change removes a copyright notice that was accidentally copied over from another file.
2025-11-21 17:11:00 +00:00
Pratik Mankawde
e4dccfd49b refactor: Retire DisallowIncoming amendment (#6045)
Amendments activated for more than 2 years can be retired. This change retires the DisallowIncoming amendment.
2025-11-21 15:18:00 +00:00
Jingchen
57f4b4eb7f refactor: Retire Checks amendment (#6055)
Amendments activated for more than 2 years can be retired. This change retires the Checks amendment.
2025-11-21 14:19:43 +00:00
20 changed files with 85 additions and 200 deletions

View File

@@ -70,9 +70,6 @@ fi
if ! grep -q 'Dev Null' src/test/app/tx/apply_test.cpp; then
echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/app/tx/apply_test.cpp)" > src/test/app/tx/apply_test.cpp
fi
if ! grep -q 'Dev Null' src/test/app/NetworkOPs_test.cpp; then
echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/app/NetworkOPs_test.cpp)" > src/test/app/NetworkOPs_test.cpp
fi
if ! grep -q 'Dev Null' src/test/rpc/ManifestRPC_test.cpp; then
echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/rpc/ManifestRPC_test.cpp)" > src/test/rpc/ManifestRPC_test.cpp
fi

View File

@@ -63,12 +63,10 @@ XRPL_FEATURE(AMM, Supported::yes, VoteBehavior::DefaultNo
XRPL_FEATURE(Clawback, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (UniversalNumber, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(XRPFees, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(DisallowIncoming, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (RemoveNFTokenAutoTrustLine, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(FlowSortStrands, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(RequireFullyCanonicalSig, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(DeletableAccounts, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(Checks, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(Flow, Supported::yes, VoteBehavior::DefaultYes)
// The following amendments are obsolete, but must remain supported
@@ -116,10 +114,12 @@ XRPL_RETIRE_FIX(STAmountCanonicalize)
XRPL_RETIRE_FIX(TakerDryOfferRemoval)
XRPL_RETIRE_FIX(TrustLinesToSelf)
XRPL_RETIRE_FEATURE(Checks)
XRPL_RETIRE_FEATURE(CheckCashMakesTrustLine)
XRPL_RETIRE_FEATURE(CryptoConditions)
XRPL_RETIRE_FEATURE(DepositAuth)
XRPL_RETIRE_FEATURE(DepositPreauth)
XRPL_RETIRE_FEATURE(DisallowIncoming)
XRPL_RETIRE_FEATURE(Escrow)
XRPL_RETIRE_FEATURE(EnforceInvariants)
XRPL_RETIRE_FEATURE(ExpandedSignerList)

View File

@@ -226,7 +226,7 @@ TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim,
#endif
TRANSACTION(ttCHECK_CREATE, 16, CheckCreate,
Delegation::delegatable,
featureChecks,
uint256{},
noPriv,
({
{sfDestination, soeREQUIRED},
@@ -242,7 +242,7 @@ TRANSACTION(ttCHECK_CREATE, 16, CheckCreate,
#endif
TRANSACTION(ttCHECK_CASH, 17, CheckCash,
Delegation::delegatable,
featureChecks,
uint256{},
noPriv,
({
{sfCheckID, soeREQUIRED},
@@ -256,7 +256,7 @@ TRANSACTION(ttCHECK_CASH, 17, CheckCash,
#endif
TRANSACTION(ttCHECK_CANCEL, 18, CheckCancel,
Delegation::delegatable,
featureChecks,
uint256{},
noPriv,
({
{sfCheckID, soeREQUIRED},

View File

@@ -67,8 +67,6 @@ public:
class Check_test : public beast::unit_test::suite
{
FeatureBitset const disallowIncoming{featureDisallowIncoming};
static uint256
getCheckIndex(AccountID const& account, std::uint32_t uSequence)
{
@@ -125,25 +123,6 @@ class Check_test : public beast::unit_test::suite
using namespace test::jtx;
Account const alice{"alice"};
{
// If the Checks amendment is not enabled, you should not be able
// to create, cash, or cancel checks.
Env env{*this, features - featureChecks};
env.fund(XRP(1000), alice);
env.close();
uint256 const checkId{
getCheckIndex(env.master, env.seq(env.master))};
env(check::create(env.master, alice, XRP(100)), ter(temDISABLED));
env.close();
env(check::cash(alice, checkId, XRP(100)), ter(temDISABLED));
env.close();
env(check::cancel(alice, checkId), ter(temDISABLED));
env.close();
}
{
// If the Checks amendment is enabled all check-related
// facilities should be available.
@@ -277,24 +256,12 @@ class Check_test : public beast::unit_test::suite
using namespace test::jtx;
// test flag doesn't set unless amendment enabled
{
Env env{*this, features - disallowIncoming};
Account const alice{"alice"};
env.fund(XRP(10000), alice);
env(fset(alice, asfDisallowIncomingCheck));
env.close();
auto const sle = env.le(alice);
uint32_t flags = sle->getFlags();
BEAST_EXPECT(!(flags & lsfDisallowIncomingCheck));
}
Account const gw{"gateway"};
Account const alice{"alice"};
Account const bob{"bob"};
IOU const USD{gw["USD"]};
Env env{*this, features | disallowIncoming};
Env env{*this, features};
STAmount const startBalance{XRP(1000).value()};
env.fund(startBalance, gw, alice, bob);
@@ -2613,7 +2580,6 @@ public:
{
using namespace test::jtx;
auto const sa = testable_amendments();
testWithFeats(sa - disallowIncoming);
testWithFeats(sa);
testTrustLineCreation(sa);
}

View File

@@ -1703,9 +1703,6 @@ class Delegate_test : public beast::unit_test::suite
// NFTokenMint, NFTokenBurn, NFTokenCreateOffer, NFTokenCancelOffer,
// NFTokenAcceptOffer are not included, they are tested separately.
std::unordered_map<std::string, uint256> txRequiredFeatures{
{"CheckCreate", featureChecks},
{"CheckCash", featureChecks},
{"CheckCancel", featureChecks},
{"Clawback", featureClawback},
{"AMMClawback", featureAMMClawback},
{"AMMCreate", featureAMM},

View File

@@ -12,8 +12,6 @@ namespace ripple {
class NFTokenBaseUtil_test : public beast::unit_test::suite
{
FeatureBitset const disallowIncoming{featureDisallowIncoming};
// Helper function that returns the number of NFTs minted by an issuer.
static std::uint32_t
mintedCount(test::jtx::Env const& env, test::jtx::Account const& issuer)
@@ -2960,19 +2958,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite
using namespace test::jtx;
// test flag doesn't set unless amendment enabled
{
Env env{*this, features - disallowIncoming};
Account const alice{"alice"};
env.fund(XRP(10000), alice);
env(fset(alice, asfDisallowIncomingNFTokenOffer));
env.close();
auto const sle = env.le(alice);
uint32_t flags = sle->getFlags();
BEAST_EXPECT(!(flags & lsfDisallowIncomingNFTokenOffer));
}
Env env{*this, features | disallowIncoming};
Env env{*this, features};
Account const issuer{"issuer"};
Account const minter{"minter"};
@@ -7624,8 +7610,8 @@ class NFTokenDisallowIncoming_test : public NFTokenBaseUtil_test
run() override
{
testWithFeats(
allFeatures - featureDisallowIncoming - fixNFTokenReserve -
featureNFTokenMintOffer - featureDynamicNFT);
allFeatures - fixNFTokenReserve - featureNFTokenMintOffer -
featureDynamicNFT);
}
};

View File

@@ -1,5 +1,3 @@
// Copyright (c) 2020 Dev Null Productions
#include <test/jtx.h>
#include <test/jtx/CaptureLogs.h>
#include <test/jtx/Env.h>

View File

@@ -14,8 +14,6 @@ using namespace jtx::paychan;
struct PayChan_test : public beast::unit_test::suite
{
FeatureBitset const disallowIncoming{featureDisallowIncoming};
static std::pair<uint256, std::shared_ptr<SLE const>>
channelKeyAndSle(
ReadView const& view,
@@ -242,20 +240,8 @@ struct PayChan_test : public beast::unit_test::suite
testcase("Disallow Incoming Flag");
using namespace jtx;
// test flag doesn't set unless amendment enabled
{
Env env{*this, features - disallowIncoming};
Account const alice{"alice"};
env.fund(XRP(10000), alice);
env(fset(alice, asfDisallowIncomingPayChan));
env.close();
auto const sle = env.le(alice);
uint32_t flags = sle->getFlags();
BEAST_EXPECT(!(flags & lsfDisallowIncomingPayChan));
}
using namespace std::literals::chrono_literals;
Env env{*this, features | disallowIncoming};
Env env{*this, features};
auto const alice = Account("alice");
auto const bob = Account("bob");
auto const cho = Account("cho");
@@ -2127,7 +2113,6 @@ public:
{
using namespace test::jtx;
FeatureBitset const all{testable_amendments()};
testWithFeats(all - disallowIncoming);
testWithFeats(all);
testDepositAuthCreds();
testMetaAndOwnership(all - fixIncludeKeyletFields);

View File

@@ -9,8 +9,6 @@ namespace test {
class SetTrust_test : public beast::unit_test::suite
{
FeatureBitset const disallowIncoming{featureDisallowIncoming};
public:
void
testTrustLineDelete()
@@ -478,25 +476,12 @@ public:
using namespace test::jtx;
// test flag doesn't set unless amendment enabled
{
Env env{*this, features - disallowIncoming};
Account const alice{"alice"};
env.fund(XRP(10000), alice);
env(fset(alice, asfDisallowIncomingTrustline));
env.close();
auto const sle = env.le(alice);
uint32_t flags = sle->getFlags();
BEAST_EXPECT(!(flags & lsfDisallowIncomingTrustline));
}
// fixDisallowIncomingV1
{
for (bool const withFix : {true, false})
{
auto const amend = withFix
? features | disallowIncoming
: (features | disallowIncoming) - fixDisallowIncomingV1;
auto const amend =
withFix ? features : features - fixDisallowIncomingV1;
Env env{*this, amend};
auto const dist = Account("dist");
@@ -532,7 +517,7 @@ public:
}
}
Env env{*this, features | disallowIncoming};
Env env{*this, features};
auto const gw = Account{"gateway"};
auto const alice = Account{"alice"};
@@ -630,7 +615,6 @@ public:
{
using namespace test::jtx;
auto const sa = testable_amendments();
testWithFeats(sa - disallowIncoming);
testWithFeats(sa);
}
};

View File

@@ -615,33 +615,23 @@ public:
{"disallowIncomingTrustline",
asfDisallowIncomingTrustline}}};
if (features[featureDisallowIncoming])
for (auto& asf : disallowIncomingFlags)
{
for (auto& asf : disallowIncomingFlags)
{
// Clear a flag and check that account_info returns results
// as expected
env(fclear(alice, asf.second));
env.close();
auto const f1 = getAccountFlag(asf.first, alice);
BEAST_EXPECT(f1.has_value());
BEAST_EXPECT(!f1.value());
// Clear a flag and check that account_info returns results
// as expected
env(fclear(alice, asf.second));
env.close();
auto const f1 = getAccountFlag(asf.first, alice);
BEAST_EXPECT(f1.has_value());
BEAST_EXPECT(!f1.value());
// Set a flag and check that account_info returns results
// as expected
env(fset(alice, asf.second));
env.close();
auto const f2 = getAccountFlag(asf.first, alice);
BEAST_EXPECT(f2.has_value());
BEAST_EXPECT(f2.value());
}
}
else
{
for (auto& asf : disallowIncomingFlags)
{
BEAST_EXPECT(!getAccountFlag(asf.first, alice));
}
// Set a flag and check that account_info returns results
// as expected
env(fset(alice, asf.second));
env.close();
auto const f2 = getAccountFlag(asf.first, alice);
BEAST_EXPECT(f2.has_value());
BEAST_EXPECT(f2.value());
}
static constexpr std::pair<std::string_view, std::uint32_t>
@@ -706,12 +696,8 @@ public:
FeatureBitset const allFeatures{
ripple::test::jtx::testable_amendments()};
testAccountFlags(allFeatures);
testAccountFlags(allFeatures - featureDisallowIncoming);
testAccountFlags(
allFeatures - featureDisallowIncoming - featureClawback);
testAccountFlags(
allFeatures - featureDisallowIncoming - featureClawback -
featureTokenEscrow);
testAccountFlags(allFeatures - featureClawback);
testAccountFlags(allFeatures - featureClawback - featureTokenEscrow);
}
};

View File

@@ -171,7 +171,7 @@ getRowsMinMax(soci::session& session, TableType type)
bool
saveValidatedLedger(
DatabaseCon& ldgDB,
DatabaseCon& txnDB,
std::unique_ptr<DatabaseCon> const& txnDB,
Application& app,
std::shared_ptr<Ledger const> const& ledger,
bool current)
@@ -254,7 +254,15 @@ saveValidatedLedger(
if (app.config().useTxTables())
{
auto db = txnDB.checkoutDb();
if (!txnDB)
{
// LCOV_EXCL_START
JLOG(j.fatal()) << "TxTables db isn't available";
Throw<std::runtime_error>("TxTables db isn't available");
// LCOV_EXCL_STOP
}
auto db = txnDB->checkoutDb();
soci::transaction tr(*db);

View File

@@ -111,7 +111,7 @@ getRowsMinMax(soci::session& session, TableType type);
bool
saveValidatedLedger(
DatabaseCon& ldgDB,
DatabaseCon& txnDB,
std::unique_ptr<DatabaseCon> const& txnDB,
Application& app,
std::shared_ptr<Ledger const> const& ledger,
bool current);

View File

@@ -392,8 +392,7 @@ SQLiteDatabaseImp::saveValidatedLedger(
{
if (existsLedger())
{
if (!detail::saveValidatedLedger(
*lgrdb_, *txdb_, app_, ledger, current))
if (!detail::saveValidatedLedger(*lgrdb_, txdb_, app_, ledger, current))
return false;
}

View File

@@ -61,8 +61,7 @@ CreateCheck::preclaim(PreclaimContext const& ctx)
auto const flags = sleDst->getFlags();
// Check if the destination has disallowed incoming checks
if (ctx.view.rules().enabled(featureDisallowIncoming) &&
(flags & lsfDisallowIncomingCheck))
if (flags & lsfDisallowIncomingCheck)
return tecNO_PERMISSION;
// Pseudo-accounts cannot cash checks. Note, this is not amendment-gated

View File

@@ -919,31 +919,21 @@ tokenOfferCreatePreclaim(
return tecNO_DST;
// check if the destination has disallowed incoming offers
if (view.rules().enabled(featureDisallowIncoming))
{
// flag cannot be set unless amendment is enabled but
// out of an abundance of caution check anyway
if (sleDst->getFlags() & lsfDisallowIncomingNFTokenOffer)
return tecNO_PERMISSION;
}
if (sleDst->getFlags() & lsfDisallowIncomingNFTokenOffer)
return tecNO_PERMISSION;
}
if (owner)
{
// Check if the owner (buy offer) has disallowed incoming offers
if (view.rules().enabled(featureDisallowIncoming))
{
auto const sleOwner = view.read(keylet::account(*owner));
auto const sleOwner = view.read(keylet::account(*owner));
// defensively check
// it should not be possible to specify owner that doesn't exist
if (!sleOwner)
return tecNO_TARGET;
// defensively check
// it should not be possible to specify owner that doesn't exist
if (!sleOwner)
return tecNO_TARGET;
if (sleOwner->getFlags() & lsfDisallowIncomingNFTokenOffer)
return tecNO_PERMISSION;
}
if (sleOwner->getFlags() & lsfDisallowIncomingNFTokenOffer)
return tecNO_PERMISSION;
}
if (view.rules().enabled(fixEnforceNFTokenTrustlineV2) && !amount.native())

View File

@@ -202,8 +202,7 @@ PayChanCreate::preclaim(PreclaimContext const& ctx)
auto const flags = sled->getFlags();
// Check if they have disallowed incoming payment channels
if (ctx.view.rules().enabled(featureDisallowIncoming) &&
(flags & lsfDisallowIncomingPayChan))
if (flags & lsfDisallowIncomingPayChan)
return tecNO_PERMISSION;
if ((flags & lsfRequireDestTag) && !ctx.tx[~sfDestinationTag])

View File

@@ -595,29 +595,25 @@ SetAccount::doApply()
sle->isFieldPresent(sfNFTokenMinter))
sle->makeFieldAbsent(sfNFTokenMinter);
// Set or clear flags for disallowing various incoming instruments
if (ctx_.view().rules().enabled(featureDisallowIncoming))
{
if (uSetFlag == asfDisallowIncomingNFTokenOffer)
uFlagsOut |= lsfDisallowIncomingNFTokenOffer;
else if (uClearFlag == asfDisallowIncomingNFTokenOffer)
uFlagsOut &= ~lsfDisallowIncomingNFTokenOffer;
if (uSetFlag == asfDisallowIncomingNFTokenOffer)
uFlagsOut |= lsfDisallowIncomingNFTokenOffer;
else if (uClearFlag == asfDisallowIncomingNFTokenOffer)
uFlagsOut &= ~lsfDisallowIncomingNFTokenOffer;
if (uSetFlag == asfDisallowIncomingCheck)
uFlagsOut |= lsfDisallowIncomingCheck;
else if (uClearFlag == asfDisallowIncomingCheck)
uFlagsOut &= ~lsfDisallowIncomingCheck;
if (uSetFlag == asfDisallowIncomingCheck)
uFlagsOut |= lsfDisallowIncomingCheck;
else if (uClearFlag == asfDisallowIncomingCheck)
uFlagsOut &= ~lsfDisallowIncomingCheck;
if (uSetFlag == asfDisallowIncomingPayChan)
uFlagsOut |= lsfDisallowIncomingPayChan;
else if (uClearFlag == asfDisallowIncomingPayChan)
uFlagsOut &= ~lsfDisallowIncomingPayChan;
if (uSetFlag == asfDisallowIncomingPayChan)
uFlagsOut |= lsfDisallowIncomingPayChan;
else if (uClearFlag == asfDisallowIncomingPayChan)
uFlagsOut &= ~lsfDisallowIncomingPayChan;
if (uSetFlag == asfDisallowIncomingTrustline)
uFlagsOut |= lsfDisallowIncomingTrustline;
else if (uClearFlag == asfDisallowIncomingTrustline)
uFlagsOut &= ~lsfDisallowIncomingTrustline;
}
if (uSetFlag == asfDisallowIncomingTrustline)
uFlagsOut |= lsfDisallowIncomingTrustline;
else if (uClearFlag == asfDisallowIncomingTrustline)
uFlagsOut &= ~lsfDisallowIncomingTrustline;
// Set or clear flags for disallowing escrow
if (ctx_.view().rules().enabled(featureTokenEscrow))

View File

@@ -200,31 +200,27 @@ SetTrust::preclaim(PreclaimContext const& ctx)
// This might be nullptr
auto const sleDst = ctx.view.read(keylet::account(uDstAccountID));
if ((ctx.view.rules().enabled(featureDisallowIncoming) ||
ammEnabled(ctx.view.rules()) ||
if ((ammEnabled(ctx.view.rules()) ||
ctx.view.rules().enabled(featureSingleAssetVault)) &&
sleDst == nullptr)
return tecNO_DST;
// If the destination has opted to disallow incoming trustlines
// then honour that flag
if (ctx.view.rules().enabled(featureDisallowIncoming))
if (sleDst->getFlags() & lsfDisallowIncomingTrustline)
{
if (sleDst->getFlags() & lsfDisallowIncomingTrustline)
// The original implementation of featureDisallowIncoming was
// too restrictive. If
// o fixDisallowIncomingV1 is enabled and
// o The trust line already exists
// Then allow the TrustSet.
if (ctx.view.rules().enabled(fixDisallowIncomingV1) &&
ctx.view.exists(keylet::line(id, uDstAccountID, currency)))
{
// The original implementation of featureDisallowIncoming was
// too restrictive. If
// o fixDisallowIncomingV1 is enabled and
// o The trust line already exists
// Then allow the TrustSet.
if (ctx.view.rules().enabled(fixDisallowIncomingV1) &&
ctx.view.exists(keylet::line(id, uDstAccountID, currency)))
{
// pass
}
else
return tecNO_PERMISSION;
// pass
}
else
return tecNO_PERMISSION;
}
// In general, trust lines to pseudo accounts are not permitted, unless

View File

@@ -121,6 +121,8 @@ VaultWithdraw::preclaim(PreclaimContext const& ctx)
if (auto const ret = checkFrozen(ctx.view, dstAcct, vaultAsset))
return ret;
// Cannot return shares to the vault, if the underlying asset was frozen for
// the submitter
if (auto const ret = checkFrozen(ctx.view, account, vaultShare))
return ret;

View File

@@ -116,11 +116,8 @@ doAccountInfo(RPC::JsonContext& context)
for (auto const& lsf : lsFlags)
acctFlags[lsf.first.data()] = sleAccepted->isFlag(lsf.second);
if (ledger->rules().enabled(featureDisallowIncoming))
{
for (auto const& lsf : disallowIncomingFlags)
acctFlags[lsf.first.data()] = sleAccepted->isFlag(lsf.second);
}
for (auto const& lsf : disallowIncomingFlags)
acctFlags[lsf.first.data()] = sleAccepted->isFlag(lsf.second);
if (ledger->rules().enabled(featureClawback))
acctFlags[allowTrustLineClawbackFlag.first.data()] =