mirror of
				https://github.com/XRPLF/rippled.git
				synced 2025-11-04 11:15:56 +00:00 
			
		
		
		
	Retire Flow Cross amendment (#5562)
The FlowCross amendment is now permanently enabled, so all code branches that have this amendment disabled are removed.
This commit is contained in:
		@@ -98,7 +98,6 @@ XRPL_FEATURE(HardenedValidations,        Supported::yes, VoteBehavior::DefaultYe
 | 
			
		||||
// fix1781: XRPEndpointSteps should be included in the circular payment check
 | 
			
		||||
XRPL_FIX    (1781,                       Supported::yes, VoteBehavior::DefaultYes)
 | 
			
		||||
XRPL_FEATURE(RequireFullyCanonicalSig,   Supported::yes, VoteBehavior::DefaultYes)
 | 
			
		||||
// fixQualityUpperBound should be activated before FlowCross
 | 
			
		||||
XRPL_FIX    (QualityUpperBound,          Supported::yes, VoteBehavior::DefaultYes)
 | 
			
		||||
XRPL_FEATURE(DeletableAccounts,          Supported::yes, VoteBehavior::DefaultYes)
 | 
			
		||||
XRPL_FIX    (PayChanRecipientOwnerDir,   Supported::yes, VoteBehavior::DefaultYes)
 | 
			
		||||
@@ -116,7 +115,6 @@ XRPL_FIX    (1571,                       Supported::yes, VoteBehavior::DefaultYe
 | 
			
		||||
XRPL_FEATURE(Checks,                     Supported::yes, VoteBehavior::DefaultYes)
 | 
			
		||||
XRPL_FEATURE(DepositAuth,                Supported::yes, VoteBehavior::DefaultYes)
 | 
			
		||||
XRPL_FIX    (1513,                       Supported::yes, VoteBehavior::DefaultYes)
 | 
			
		||||
XRPL_FEATURE(FlowCross,                  Supported::yes, VoteBehavior::DefaultYes)
 | 
			
		||||
XRPL_FEATURE(Flow,                       Supported::yes, VoteBehavior::DefaultYes)
 | 
			
		||||
 | 
			
		||||
// The following amendments are obsolete, but must remain supported
 | 
			
		||||
@@ -159,3 +157,4 @@ XRPL_RETIRE(fix1201)
 | 
			
		||||
XRPL_RETIRE(fix1512)
 | 
			
		||||
XRPL_RETIRE(fix1523)
 | 
			
		||||
XRPL_RETIRE(fix1528)
 | 
			
		||||
XRPL_RETIRE(FlowCross)
 | 
			
		||||
 
 | 
			
		||||
@@ -77,10 +77,8 @@ public:
 | 
			
		||||
        auto const gw = Account("gateway");
 | 
			
		||||
        auto const USD = gw["USD"];
 | 
			
		||||
 | 
			
		||||
        // The number of allowed offers to cross is different between
 | 
			
		||||
        // Taker and FlowCross.  Taker allows 850 and FlowCross allows 1000.
 | 
			
		||||
        // Accommodate that difference in the test.
 | 
			
		||||
        int const maxConsumed = features[featureFlowCross] ? 1000 : 850;
 | 
			
		||||
        // The payment engine allows 1000 offers to cross.
 | 
			
		||||
        int const maxConsumed = 1000;
 | 
			
		||||
 | 
			
		||||
        env.fund(XRP(100000000), gw, "alice", "bob", "carol");
 | 
			
		||||
        int const bobsOfferCount = maxConsumed + 150;
 | 
			
		||||
@@ -119,11 +117,8 @@ public:
 | 
			
		||||
 | 
			
		||||
        env.fund(XRP(100000000), gw, "alice", "bob", "carol", "dan", "evita");
 | 
			
		||||
 | 
			
		||||
        // The number of offers allowed to cross is different between
 | 
			
		||||
        // Taker and FlowCross.  Taker allows 850 and FlowCross allows 1000.
 | 
			
		||||
        // Accommodate that difference in the test.
 | 
			
		||||
        bool const isFlowCross{features[featureFlowCross]};
 | 
			
		||||
        int const maxConsumed = isFlowCross ? 1000 : 850;
 | 
			
		||||
        // The payment engine allows 1000 offers to cross.
 | 
			
		||||
        int const maxConsumed = 1000;
 | 
			
		||||
 | 
			
		||||
        int const evitasOfferCount{maxConsumed + 49};
 | 
			
		||||
        env.trust(USD(1000), "alice");
 | 
			
		||||
@@ -133,14 +128,8 @@ public:
 | 
			
		||||
        env.trust(USD(evitasOfferCount + 1), "evita");
 | 
			
		||||
        env(pay(gw, "evita", USD(evitasOfferCount + 1)));
 | 
			
		||||
 | 
			
		||||
        // Taker and FlowCross have another difference we must accommodate.
 | 
			
		||||
        // Taker allows a total of 1000 unfunded offers to be consumed
 | 
			
		||||
        // beyond the 850 offers it can take.  FlowCross draws no such
 | 
			
		||||
        // distinction; its limit is 1000 funded or unfunded.
 | 
			
		||||
        //
 | 
			
		||||
        // Give carol an extra 150 (unfunded) offers when we're using Taker
 | 
			
		||||
        // to accommodate that difference.
 | 
			
		||||
        int const carolsOfferCount{isFlowCross ? 700 : 850};
 | 
			
		||||
        // The payment engine has a limit of 1000 funded or unfunded offers.
 | 
			
		||||
        int const carolsOfferCount{700};
 | 
			
		||||
        n_offers(env, 400, "alice", XRP(1), USD(1));
 | 
			
		||||
        n_offers(env, carolsOfferCount, "carol", XRP(1), USD(1));
 | 
			
		||||
        n_offers(env, evitasOfferCount, "evita", XRP(1), USD(1));
 | 
			
		||||
@@ -268,9 +257,9 @@ public:
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    testAutoBridgedLimitsFlowCross(FeatureBitset features)
 | 
			
		||||
    testAutoBridgedLimits(FeatureBitset features)
 | 
			
		||||
    {
 | 
			
		||||
        testcase("Auto Bridged Limits FlowCross");
 | 
			
		||||
        testcase("Auto Bridged Limits");
 | 
			
		||||
 | 
			
		||||
        // If any book step in a payment strand consumes 1000 offers, the
 | 
			
		||||
        // liquidity from the offers is used, but that strand will be marked as
 | 
			
		||||
@@ -452,26 +441,6 @@ public:
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    testAutoBridgedLimits(FeatureBitset features)
 | 
			
		||||
    {
 | 
			
		||||
        // Taker and FlowCross are too different in the way they handle
 | 
			
		||||
        // autobridging to make one test suit both approaches.
 | 
			
		||||
        //
 | 
			
		||||
        //  o Taker alternates between books, completing one full increment
 | 
			
		||||
        //    before returning to make another pass.
 | 
			
		||||
        //
 | 
			
		||||
        //  o FlowCross extracts as much as possible in one book at one Quality
 | 
			
		||||
        //    before proceeding to the other book.  This reduces the number of
 | 
			
		||||
        //    times we change books.
 | 
			
		||||
        //
 | 
			
		||||
        // So the tests for the two forms of autobridging are separate.
 | 
			
		||||
        if (features[featureFlowCross])
 | 
			
		||||
            testAutoBridgedLimitsFlowCross(features);
 | 
			
		||||
        else
 | 
			
		||||
            testAutoBridgedLimitsTaker(features);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    testOfferOverflow(FeatureBitset features)
 | 
			
		||||
    {
 | 
			
		||||
@@ -522,11 +491,10 @@ public:
 | 
			
		||||
        n_offers(env, 998, alice, XRP(0.96), USD(1));
 | 
			
		||||
        n_offers(env, 998, alice, XRP(0.95), USD(1));
 | 
			
		||||
 | 
			
		||||
        bool const withFlowCross = features[featureFlowCross];
 | 
			
		||||
        bool const withSortStrands = features[featureFlowSortStrands];
 | 
			
		||||
 | 
			
		||||
        auto const expectedTER = [&]() -> TER {
 | 
			
		||||
            if (withFlowCross && !withSortStrands)
 | 
			
		||||
            if (!withSortStrands)
 | 
			
		||||
                return TER{tecOVERSIZE};
 | 
			
		||||
            return tesSUCCESS;
 | 
			
		||||
        }();
 | 
			
		||||
@@ -535,8 +503,6 @@ public:
 | 
			
		||||
        env.close();
 | 
			
		||||
 | 
			
		||||
        auto const expectedUSD = [&] {
 | 
			
		||||
            if (!withFlowCross)
 | 
			
		||||
                return USD(850);
 | 
			
		||||
            if (!withSortStrands)
 | 
			
		||||
                return USD(0);
 | 
			
		||||
            return USD(1996);
 | 
			
		||||
@@ -558,11 +524,9 @@ public:
 | 
			
		||||
        using namespace jtx;
 | 
			
		||||
        auto const sa = supported_amendments();
 | 
			
		||||
        testAll(sa);
 | 
			
		||||
        testAll(sa - featureFlowSortStrands);
 | 
			
		||||
        testAll(sa - featurePermissionedDEX);
 | 
			
		||||
        testAll(sa - featureFlowSortStrands - featurePermissionedDEX);
 | 
			
		||||
        testAll(
 | 
			
		||||
            sa - featureFlowCross - featureFlowSortStrands -
 | 
			
		||||
            featurePermissionedDEX);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -143,8 +143,6 @@ public:
 | 
			
		||||
    {
 | 
			
		||||
        using namespace jtx;
 | 
			
		||||
        auto const sa = supported_amendments();
 | 
			
		||||
        test_convert_all_of_an_asset(
 | 
			
		||||
            sa - featureFlowCross - featurePermissionedDEX);
 | 
			
		||||
        test_convert_all_of_an_asset(sa - featurePermissionedDEX);
 | 
			
		||||
        test_convert_all_of_an_asset(sa);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -147,7 +147,6 @@ public:
 | 
			
		||||
    {
 | 
			
		||||
        using namespace test::jtx;
 | 
			
		||||
        auto const sa = supported_amendments();
 | 
			
		||||
        testXRPDiscrepancy(sa - featureFlowCross - featurePermissionedDEX);
 | 
			
		||||
        testXRPDiscrepancy(sa - featurePermissionedDEX);
 | 
			
		||||
        testXRPDiscrepancy(sa);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1333,7 +1333,6 @@ struct Flow_test : public beast::unit_test::suite
 | 
			
		||||
 | 
			
		||||
        using namespace jtx;
 | 
			
		||||
        auto const sa = supported_amendments();
 | 
			
		||||
        testWithFeats(sa - featureFlowCross - featurePermissionedDEX);
 | 
			
		||||
        testWithFeats(sa - featurePermissionedDEX);
 | 
			
		||||
        testWithFeats(sa);
 | 
			
		||||
        testEmptyStrand(sa);
 | 
			
		||||
@@ -1347,12 +1346,9 @@ struct Flow_manual_test : public Flow_test
 | 
			
		||||
    {
 | 
			
		||||
        using namespace jtx;
 | 
			
		||||
        auto const all = supported_amendments();
 | 
			
		||||
        FeatureBitset const flowCross{featureFlowCross};
 | 
			
		||||
        FeatureBitset const f1513{fix1513};
 | 
			
		||||
        FeatureBitset const permDex{featurePermissionedDEX};
 | 
			
		||||
 | 
			
		||||
        testWithFeats(all - flowCross - f1513 - permDex);
 | 
			
		||||
        testWithFeats(all - flowCross - permDex);
 | 
			
		||||
        testWithFeats(all - f1513 - permDex);
 | 
			
		||||
        testWithFeats(all - permDex);
 | 
			
		||||
        testWithFeats(all);
 | 
			
		||||
 
 | 
			
		||||
@@ -961,24 +961,12 @@ class Freeze_test : public beast::unit_test::suite
 | 
			
		||||
            env.close();
 | 
			
		||||
 | 
			
		||||
            // test: A1 wants to buy, must fail
 | 
			
		||||
            if (features[featureFlowCross])
 | 
			
		||||
            {
 | 
			
		||||
                env(offer(A1, USD(1), XRP(2)),
 | 
			
		||||
                    txflags(tfFillOrKill),
 | 
			
		||||
                    ter(tecKILLED));
 | 
			
		||||
                env.close();
 | 
			
		||||
                env.require(
 | 
			
		||||
                    balance(A1, USD(1002)),
 | 
			
		||||
                    balance(A2, USD(997)),
 | 
			
		||||
                    offers(A1, 0));
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // The transaction that should be here would succeed.
 | 
			
		||||
                // I don't want to adjust balances in following tests. Flow
 | 
			
		||||
                // cross feature flag is not relevant to this particular test
 | 
			
		||||
                // case so we're not missing out some corner cases checks.
 | 
			
		||||
            }
 | 
			
		||||
            env(offer(A1, USD(1), XRP(2)),
 | 
			
		||||
                txflags(tfFillOrKill),
 | 
			
		||||
                ter(tecKILLED));
 | 
			
		||||
            env.close();
 | 
			
		||||
            env.require(
 | 
			
		||||
                balance(A1, USD(1002)), balance(A2, USD(997)), offers(A1, 0));
 | 
			
		||||
 | 
			
		||||
            // test: A1 can create passive sell offer
 | 
			
		||||
            env(offer(A1, XRP(2), USD(1)), txflags(tfPassive));
 | 
			
		||||
@@ -2107,17 +2095,14 @@ public:
 | 
			
		||||
        };
 | 
			
		||||
        using namespace test::jtx;
 | 
			
		||||
        auto const sa = supported_amendments();
 | 
			
		||||
        testAll(
 | 
			
		||||
            sa - featureFlowCross - featureDeepFreeze - featurePermissionedDEX -
 | 
			
		||||
            fixEnforceNFTokenTrustlineV2);
 | 
			
		||||
        testAll(
 | 
			
		||||
            sa - featureFlowCross - featurePermissionedDEX -
 | 
			
		||||
            fixEnforceNFTokenTrustlineV2);
 | 
			
		||||
        testAll(
 | 
			
		||||
            sa - featureDeepFreeze - featurePermissionedDEX -
 | 
			
		||||
            fixEnforceNFTokenTrustlineV2);
 | 
			
		||||
        testAll(sa - featurePermissionedDEX - fixEnforceNFTokenTrustlineV2);
 | 
			
		||||
        testAll(sa - featureDeepFreeze - featurePermissionedDEX);
 | 
			
		||||
        testAll(sa - featurePermissionedDEX);
 | 
			
		||||
        testAll(sa - fixEnforceNFTokenTrustlineV2);
 | 
			
		||||
        testAll(sa - featureDeepFreeze);
 | 
			
		||||
        testAll(sa);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -1343,18 +1343,10 @@ public:
 | 
			
		||||
 | 
			
		||||
        // NOTE :
 | 
			
		||||
        // At this point, all offers are expected to be consumed.
 | 
			
		||||
        // Alas, they are not - because of a bug in the Taker auto-bridging
 | 
			
		||||
        // implementation which is addressed by fixTakerDryOfferRemoval.
 | 
			
		||||
        // The pre-fixTakerDryOfferRemoval implementation (incorrect) leaves
 | 
			
		||||
        // an empty offer in the second leg of the bridge. Validate both the
 | 
			
		||||
        // old and the new behavior.
 | 
			
		||||
        {
 | 
			
		||||
            auto acctOffers = offersOnAccount(env, account_to_test);
 | 
			
		||||
            bool const noStaleOffers{
 | 
			
		||||
                features[featureFlowCross] ||
 | 
			
		||||
                features[fixTakerDryOfferRemoval]};
 | 
			
		||||
 | 
			
		||||
            BEAST_EXPECT(acctOffers.size() == (noStaleOffers ? 0 : 1));
 | 
			
		||||
            BEAST_EXPECT(acctOffers.size() == 0);
 | 
			
		||||
            for (auto const& offerPtr : acctOffers)
 | 
			
		||||
            {
 | 
			
		||||
                auto const& offer = *offerPtr;
 | 
			
		||||
@@ -1464,8 +1456,7 @@ public:
 | 
			
		||||
            std::uint32_t const bobOfferSeq = env.seq(bob);
 | 
			
		||||
            env(offer(bob, XRP(2000), USD(1)));
 | 
			
		||||
 | 
			
		||||
            if (localFeatures[featureFlowCross] &&
 | 
			
		||||
                localFeatures[fixReducedOffersV2])
 | 
			
		||||
            if (localFeatures[fixReducedOffersV2])
 | 
			
		||||
            {
 | 
			
		||||
                // With the rounding introduced by fixReducedOffersV2, bob's
 | 
			
		||||
                // offer does not cross alice's offer and goes straight into
 | 
			
		||||
@@ -1489,8 +1480,7 @@ public:
 | 
			
		||||
            // crossing algorithms becomes apparent.  The old offer crossing
 | 
			
		||||
            // would consume small_amount and transfer no XRP.  The new offer
 | 
			
		||||
            // crossing transfers a single drop, rather than no drops.
 | 
			
		||||
            auto const crossingDelta =
 | 
			
		||||
                localFeatures[featureFlowCross] ? drops(1) : drops(0);
 | 
			
		||||
            auto const crossingDelta = drops(1);
 | 
			
		||||
 | 
			
		||||
            jrr = ledgerEntryState(env, alice, gw, "USD");
 | 
			
		||||
            BEAST_EXPECT(
 | 
			
		||||
@@ -2044,15 +2034,9 @@ public:
 | 
			
		||||
 | 
			
		||||
        env.require(balance(carol, USD(0)));
 | 
			
		||||
        env.require(balance(carol, EUR(none)));
 | 
			
		||||
        // If neither featureFlowCross nor fixTakerDryOfferRemoval are defined
 | 
			
		||||
        // then carol's offer will be left on the books, but with zero value.
 | 
			
		||||
        int const emptyOfferCount{
 | 
			
		||||
            features[featureFlowCross] || features[fixTakerDryOfferRemoval]
 | 
			
		||||
                ? 0
 | 
			
		||||
                : 1};
 | 
			
		||||
 | 
			
		||||
        env.require(offers(carol, 0 + emptyOfferCount));
 | 
			
		||||
        env.require(owners(carol, 1 + emptyOfferCount));
 | 
			
		||||
        env.require(offers(carol, 0));
 | 
			
		||||
        env.require(owners(carol, 1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
@@ -4236,22 +4220,13 @@ public:
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // clang-format off
 | 
			
		||||
        TestData const takerTests[]{
 | 
			
		||||
            //      btcStart    ------------------- actor[0] --------------------    ------------------- actor[1] --------------------
 | 
			
		||||
            {0, 0, 1, BTC(5), {{"deb", 0, drops(3900000'000000 - 4 * baseFee), BTC(5), USD(3000)}, {"dan", 0, drops(4100000'000000 - 3 * baseFee), BTC(0), USD(750)}}}, // no BTC xfer fee
 | 
			
		||||
            {0, 0, 0, BTC(5), {{"flo", 0, drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)}                                                    }}  // no xfer fee
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        TestData const flowTests[]{
 | 
			
		||||
        TestData const tests[]{
 | 
			
		||||
            //         btcStart    ------------------- actor[0] --------------------    ------------------- actor[1] --------------------
 | 
			
		||||
            {0, 0, 1, BTC(5), {{"gay", 1, drops(3950000'000000 - 4 * baseFee), BTC(5), USD(2500)}, {"gar", 1, drops(4050000'000000 - 3 * baseFee), BTC(0), USD(1375)}}}, // no BTC xfer fee
 | 
			
		||||
            {0, 0, 0, BTC(5), {{"hye", 2, drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)}                                                     }}  // no xfer fee
 | 
			
		||||
        };
 | 
			
		||||
        // clang-format on
 | 
			
		||||
 | 
			
		||||
        // Pick the right tests.
 | 
			
		||||
        auto const& tests = features[featureFlowCross] ? flowTests : takerTests;
 | 
			
		||||
 | 
			
		||||
        for (auto const& t : tests)
 | 
			
		||||
        {
 | 
			
		||||
            Account const& self = t.actors[t.self].acct;
 | 
			
		||||
@@ -4378,9 +4353,8 @@ public:
 | 
			
		||||
        // 1. alice creates an offer to acquire USD/gw, an asset for which
 | 
			
		||||
        //    she does not have a trust line.  At some point in the future,
 | 
			
		||||
        //    gw adds lsfRequireAuth.  Then, later, alice's offer is crossed.
 | 
			
		||||
        //     a. With Taker alice's unauthorized offer is consumed.
 | 
			
		||||
        //     b. With FlowCross  alice's offer is deleted, not consumed,
 | 
			
		||||
        //        since alice is not authorized to hold USD/gw.
 | 
			
		||||
        //     Alice's offer is deleted, not consumed, since alice is not
 | 
			
		||||
        //     authorized to hold USD/gw.
 | 
			
		||||
        //
 | 
			
		||||
        // 2. alice tries to create an offer for USD/gw, now that gw has
 | 
			
		||||
        //    lsfRequireAuth set.  This time the offer create fails because
 | 
			
		||||
@@ -4428,33 +4402,17 @@ public:
 | 
			
		||||
        // gw now requires authorization and bob has gwUSD(50).  Let's see if
 | 
			
		||||
        // bob can cross alice's offer.
 | 
			
		||||
        //
 | 
			
		||||
        // o With Taker bob's offer should cross alice's.
 | 
			
		||||
        // o With FlowCross bob's offer shouldn't cross and alice's
 | 
			
		||||
        //   unauthorized offer should be deleted.
 | 
			
		||||
        // Bob's offer shouldn't cross and alice's unauthorized offer should be
 | 
			
		||||
        // deleted.
 | 
			
		||||
        env(offer(bob, XRP(4000), gwUSD(40)));
 | 
			
		||||
        env.close();
 | 
			
		||||
        std::uint32_t const bobOfferSeq = env.seq(bob) - 1;
 | 
			
		||||
 | 
			
		||||
        bool const flowCross = features[featureFlowCross];
 | 
			
		||||
 | 
			
		||||
        env.require(offers(alice, 0));
 | 
			
		||||
        if (flowCross)
 | 
			
		||||
        {
 | 
			
		||||
            // alice's unauthorized offer is deleted & bob's offer not crossed.
 | 
			
		||||
            env.require(balance(alice, gwUSD(none)));
 | 
			
		||||
            env.require(offers(bob, 1));
 | 
			
		||||
            env.require(balance(bob, gwUSD(50)));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // alice's offer crosses bob's
 | 
			
		||||
            env.require(balance(alice, gwUSD(40)));
 | 
			
		||||
            env.require(offers(bob, 0));
 | 
			
		||||
            env.require(balance(bob, gwUSD(10)));
 | 
			
		||||
 | 
			
		||||
            // The rest of the test verifies FlowCross behavior.
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // alice's unauthorized offer is deleted & bob's offer not crossed.
 | 
			
		||||
        env.require(balance(alice, gwUSD(none)));
 | 
			
		||||
        env.require(offers(bob, 1));
 | 
			
		||||
        env.require(balance(bob, gwUSD(50)));
 | 
			
		||||
 | 
			
		||||
        // See if alice can create an offer without authorization.  alice
 | 
			
		||||
        // should not be able to create the offer and bob's offer should be
 | 
			
		||||
@@ -5186,9 +5144,7 @@ public:
 | 
			
		||||
        // tfFillOrKill, TakerPays must be filled
 | 
			
		||||
        {
 | 
			
		||||
            TER const err =
 | 
			
		||||
                features[fixFillOrKill] || !features[featureFlowCross]
 | 
			
		||||
                ? TER(tesSUCCESS)
 | 
			
		||||
                : tecKILLED;
 | 
			
		||||
                features[fixFillOrKill] ? TER(tesSUCCESS) : tecKILLED;
 | 
			
		||||
 | 
			
		||||
            env(offer(maker, XRP(100), USD(100)));
 | 
			
		||||
            env.close();
 | 
			
		||||
@@ -5410,7 +5366,6 @@ public:
 | 
			
		||||
    {
 | 
			
		||||
        using namespace jtx;
 | 
			
		||||
        static FeatureBitset const all{supported_amendments()};
 | 
			
		||||
        static FeatureBitset const flowCross{featureFlowCross};
 | 
			
		||||
        static FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
 | 
			
		||||
        static FeatureBitset const rmSmallIncreasedQOffers{
 | 
			
		||||
            fixRmSmallIncreasedQOffers};
 | 
			
		||||
@@ -5419,10 +5374,9 @@ public:
 | 
			
		||||
        FeatureBitset const fillOrKill{fixFillOrKill};
 | 
			
		||||
        FeatureBitset const permDEX{featurePermissionedDEX};
 | 
			
		||||
 | 
			
		||||
        static std::array<FeatureBitset, 7> const feats{
 | 
			
		||||
        static std::array<FeatureBitset, 6> const feats{
 | 
			
		||||
            all - takerDryOffer - immediateOfferKilled - permDEX,
 | 
			
		||||
            all - flowCross - takerDryOffer - immediateOfferKilled - permDEX,
 | 
			
		||||
            all - flowCross - immediateOfferKilled - permDEX,
 | 
			
		||||
            all - immediateOfferKilled - permDEX,
 | 
			
		||||
            all - rmSmallIncreasedQOffers - immediateOfferKilled - fillOrKill -
 | 
			
		||||
                permDEX,
 | 
			
		||||
            all - fillOrKill - permDEX,
 | 
			
		||||
@@ -5444,7 +5398,7 @@ public:
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class OfferWOFlowCross_test : public OfferBaseUtil_test
 | 
			
		||||
class OfferWTakerDryOffer_test : public OfferBaseUtil_test
 | 
			
		||||
{
 | 
			
		||||
    void
 | 
			
		||||
    run() override
 | 
			
		||||
@@ -5453,7 +5407,7 @@ class OfferWOFlowCross_test : public OfferBaseUtil_test
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class OfferWTakerDryOffer_test : public OfferBaseUtil_test
 | 
			
		||||
class OfferWOSmallQOffers_test : public OfferBaseUtil_test
 | 
			
		||||
{
 | 
			
		||||
    void
 | 
			
		||||
    run() override
 | 
			
		||||
@@ -5462,7 +5416,7 @@ class OfferWTakerDryOffer_test : public OfferBaseUtil_test
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class OfferWOSmallQOffers_test : public OfferBaseUtil_test
 | 
			
		||||
class OfferWOFillOrKill_test : public OfferBaseUtil_test
 | 
			
		||||
{
 | 
			
		||||
    void
 | 
			
		||||
    run() override
 | 
			
		||||
@@ -5471,7 +5425,7 @@ class OfferWOSmallQOffers_test : public OfferBaseUtil_test
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class OfferWOFillOrKill_test : public OfferBaseUtil_test
 | 
			
		||||
class OfferWOPermDEX_test : public OfferBaseUtil_test
 | 
			
		||||
{
 | 
			
		||||
    void
 | 
			
		||||
    run() override
 | 
			
		||||
@@ -5480,21 +5434,12 @@ class OfferWOFillOrKill_test : public OfferBaseUtil_test
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class OfferWOPermDEX_test : public OfferBaseUtil_test
 | 
			
		||||
{
 | 
			
		||||
    void
 | 
			
		||||
    run() override
 | 
			
		||||
    {
 | 
			
		||||
        OfferBaseUtil_test::run(5);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class OfferAllFeatures_test : public OfferBaseUtil_test
 | 
			
		||||
{
 | 
			
		||||
    void
 | 
			
		||||
    run() override
 | 
			
		||||
    {
 | 
			
		||||
        OfferBaseUtil_test::run(6, true);
 | 
			
		||||
        OfferBaseUtil_test::run(5, true);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -5505,26 +5450,23 @@ class Offer_manual_test : public OfferBaseUtil_test
 | 
			
		||||
    {
 | 
			
		||||
        using namespace jtx;
 | 
			
		||||
        FeatureBitset const all{supported_amendments()};
 | 
			
		||||
        FeatureBitset const flowCross{featureFlowCross};
 | 
			
		||||
        FeatureBitset const f1513{fix1513};
 | 
			
		||||
        FeatureBitset const immediateOfferKilled{featureImmediateOfferKilled};
 | 
			
		||||
        FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
 | 
			
		||||
        FeatureBitset const fillOrKill{fixFillOrKill};
 | 
			
		||||
        FeatureBitset const permDEX{featurePermissionedDEX};
 | 
			
		||||
 | 
			
		||||
        testAll(all - flowCross - f1513 - immediateOfferKilled - permDEX);
 | 
			
		||||
        testAll(all - flowCross - immediateOfferKilled - permDEX);
 | 
			
		||||
        testAll(all - f1513 - immediateOfferKilled - permDEX);
 | 
			
		||||
        testAll(all - immediateOfferKilled - fillOrKill - permDEX);
 | 
			
		||||
        testAll(all - fillOrKill - permDEX);
 | 
			
		||||
        testAll(all - permDEX);
 | 
			
		||||
        testAll(all);
 | 
			
		||||
 | 
			
		||||
        testAll(all - flowCross - takerDryOffer - permDEX);
 | 
			
		||||
        testAll(all - takerDryOffer - permDEX);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, tx, ripple, 2);
 | 
			
		||||
BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFlowCross, tx, ripple, 2);
 | 
			
		||||
BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, tx, ripple, 2);
 | 
			
		||||
BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, tx, ripple, 2);
 | 
			
		||||
BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, tx, ripple, 2);
 | 
			
		||||
 
 | 
			
		||||
@@ -1268,15 +1268,12 @@ struct PayStrand_test : public beast::unit_test::suite
 | 
			
		||||
    {
 | 
			
		||||
        using namespace jtx;
 | 
			
		||||
        auto const sa = supported_amendments();
 | 
			
		||||
        testToStrand(sa - featureFlowCross - featurePermissionedDEX);
 | 
			
		||||
        testToStrand(sa - featurePermissionedDEX);
 | 
			
		||||
        testToStrand(sa);
 | 
			
		||||
 | 
			
		||||
        testRIPD1373(sa - featureFlowCross - featurePermissionedDEX);
 | 
			
		||||
        testRIPD1373(sa - featurePermissionedDEX);
 | 
			
		||||
        testRIPD1373(sa);
 | 
			
		||||
 | 
			
		||||
        testLoop(sa - featureFlowCross - featurePermissionedDEX);
 | 
			
		||||
        testLoop(sa - featurePermissionedDEX);
 | 
			
		||||
        testLoop(sa);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -207,24 +207,6 @@ class PermissionedDEX_test : public beast::unit_test::suite
 | 
			
		||||
            env.close();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // test preflight: permissioned dex cannot be used without enable
 | 
			
		||||
        // flowcross
 | 
			
		||||
        {
 | 
			
		||||
            Env env(*this, features - featureFlowCross);
 | 
			
		||||
            auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
 | 
			
		||||
                PermissionedDEX(env);
 | 
			
		||||
 | 
			
		||||
            env(offer(bob, XRP(10), USD(10)),
 | 
			
		||||
                domain(domainID),
 | 
			
		||||
                ter(temDISABLED));
 | 
			
		||||
            env.close();
 | 
			
		||||
 | 
			
		||||
            env.enableFeature(featureFlowCross);
 | 
			
		||||
            env.close();
 | 
			
		||||
            env(offer(bob, XRP(10), USD(10)), domain(domainID));
 | 
			
		||||
            env.close();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // preclaim - someone outside of the domain cannot create domain offer
 | 
			
		||||
        {
 | 
			
		||||
            Env env(*this, features);
 | 
			
		||||
 
 | 
			
		||||
@@ -75,7 +75,6 @@ struct SetAuth_test : public beast::unit_test::suite
 | 
			
		||||
    {
 | 
			
		||||
        using namespace jtx;
 | 
			
		||||
        auto const sa = supported_amendments();
 | 
			
		||||
        testAuth(sa - featureFlowCross - featurePermissionedDEX);
 | 
			
		||||
        testAuth(sa - featurePermissionedDEX);
 | 
			
		||||
        testAuth(sa);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -481,7 +481,6 @@ public:
 | 
			
		||||
 | 
			
		||||
        using namespace test::jtx;
 | 
			
		||||
        auto const sa = supported_amendments();
 | 
			
		||||
        testWithFeatures(sa - featureFlowCross - featurePermissionedDEX);
 | 
			
		||||
        testWithFeatures(sa - featurePermissionedDEX);
 | 
			
		||||
        testWithFeatures(sa);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -104,7 +104,6 @@ struct BookDirs_test : public beast::unit_test::suite
 | 
			
		||||
    {
 | 
			
		||||
        using namespace jtx;
 | 
			
		||||
        auto const sa = supported_amendments();
 | 
			
		||||
        test_bookdir(sa - featureFlowCross - featurePermissionedDEX);
 | 
			
		||||
        test_bookdir(sa - featurePermissionedDEX);
 | 
			
		||||
        test_bookdir(sa);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -421,7 +421,6 @@ public:
 | 
			
		||||
        };
 | 
			
		||||
        using namespace jtx;
 | 
			
		||||
        auto const sa = supported_amendments();
 | 
			
		||||
        testAll(sa - featureFlowCross - featurePermissionedDEX);
 | 
			
		||||
        testAll(sa - featurePermissionedDEX);
 | 
			
		||||
        testAll(sa);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -252,10 +252,7 @@ public:
 | 
			
		||||
    {
 | 
			
		||||
        using namespace jtx;
 | 
			
		||||
        auto const sa = supported_amendments();
 | 
			
		||||
        for (auto feature :
 | 
			
		||||
             {sa - featureFlowCross - featurePermissionedDEX,
 | 
			
		||||
              sa - featurePermissionedDEX,
 | 
			
		||||
              sa})
 | 
			
		||||
        for (auto feature : {sa - featurePermissionedDEX, sa})
 | 
			
		||||
        {
 | 
			
		||||
            testGWB(feature);
 | 
			
		||||
            testGWBApiVersions(feature);
 | 
			
		||||
 
 | 
			
		||||
@@ -294,7 +294,6 @@ public:
 | 
			
		||||
        };
 | 
			
		||||
        using namespace jtx;
 | 
			
		||||
        auto const sa = supported_amendments();
 | 
			
		||||
        withFeatsTests(sa - featureFlowCross - featurePermissionedDEX);
 | 
			
		||||
        withFeatsTests(sa - featurePermissionedDEX);
 | 
			
		||||
        withFeatsTests(sa);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -743,7 +743,6 @@ BookStep<TIn, TOut, TDerived>::forEachOffer(
 | 
			
		||||
    FlowOfferStream<TIn, TOut> offers(
 | 
			
		||||
        sb, afView, book_, sb.parentCloseTime(), counter, j_);
 | 
			
		||||
 | 
			
		||||
    bool const flowCross = afView.rules().enabled(featureFlowCross);
 | 
			
		||||
    bool offerAttempted = false;
 | 
			
		||||
    std::optional<Quality> ofrQ;
 | 
			
		||||
    auto execOffer = [&](auto& offer) {
 | 
			
		||||
@@ -760,8 +759,8 @@ BookStep<TIn, TOut, TDerived>::forEachOffer(
 | 
			
		||||
 | 
			
		||||
        // Make sure offer owner has authorization to own IOUs from issuer.
 | 
			
		||||
        // An account can always own XRP or their own IOUs.
 | 
			
		||||
        if (flowCross && (!isXRP(offer.issueIn().currency)) &&
 | 
			
		||||
            (offer.owner() != offer.issueIn().account))
 | 
			
		||||
        if (!isXRP(offer.issueIn().currency) &&
 | 
			
		||||
            offer.owner() != offer.issueIn().account)
 | 
			
		||||
        {
 | 
			
		||||
            auto const& issuerID = offer.issueIn().account;
 | 
			
		||||
            auto const issuer = afView.read(keylet::account(issuerID));
 | 
			
		||||
 
 | 
			
		||||
@@ -50,12 +50,6 @@ CreateOffer::preflight(PreflightContext const& ctx)
 | 
			
		||||
        !ctx.rules.enabled(featurePermissionedDEX))
 | 
			
		||||
        return temDISABLED;
 | 
			
		||||
 | 
			
		||||
    // Permissioned offers should use the PE (which must be enabled by
 | 
			
		||||
    // featureFlowCross amendment)
 | 
			
		||||
    if (ctx.rules.enabled(featurePermissionedDEX) &&
 | 
			
		||||
        !ctx.rules.enabled(featureFlowCross))
 | 
			
		||||
        return temDISABLED;
 | 
			
		||||
 | 
			
		||||
    if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
 | 
			
		||||
        return ret;
 | 
			
		||||
 | 
			
		||||
@@ -685,54 +679,6 @@ CreateOffer::step_account(OfferStream& stream, Taker const& taker)
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Fill as much of the offer as possible by consuming offers
 | 
			
		||||
// already on the books. Return the status and the amount of
 | 
			
		||||
// the offer to left unfilled.
 | 
			
		||||
std::pair<TER, Amounts>
 | 
			
		||||
CreateOffer::takerCross(
 | 
			
		||||
    Sandbox& sb,
 | 
			
		||||
    Sandbox& sbCancel,
 | 
			
		||||
    Amounts const& takerAmount)
 | 
			
		||||
{
 | 
			
		||||
    NetClock::time_point const when = sb.parentCloseTime();
 | 
			
		||||
 | 
			
		||||
    beast::WrappedSink takerSink(j_, "Taker ");
 | 
			
		||||
 | 
			
		||||
    Taker taker(
 | 
			
		||||
        cross_type_,
 | 
			
		||||
        sb,
 | 
			
		||||
        account_,
 | 
			
		||||
        takerAmount,
 | 
			
		||||
        ctx_.tx.getFlags(),
 | 
			
		||||
        beast::Journal(takerSink));
 | 
			
		||||
 | 
			
		||||
    // If the taker is unfunded before we begin crossing
 | 
			
		||||
    // there's nothing to do - just return an error.
 | 
			
		||||
    //
 | 
			
		||||
    // We check this in preclaim, but when selling XRP
 | 
			
		||||
    // charged fees can cause a user's available balance
 | 
			
		||||
    // to go to 0 (by causing it to dip below the reserve)
 | 
			
		||||
    // so we check this case again.
 | 
			
		||||
    if (taker.unfunded())
 | 
			
		||||
    {
 | 
			
		||||
        JLOG(j_.debug()) << "Not crossing: taker is unfunded.";
 | 
			
		||||
        return {tecUNFUNDED_OFFER, takerAmount};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        if (cross_type_ == CrossType::IouToIou)
 | 
			
		||||
            return bridged_cross(taker, sb, sbCancel, when);
 | 
			
		||||
 | 
			
		||||
        return direct_cross(taker, sb, sbCancel, when);
 | 
			
		||||
    }
 | 
			
		||||
    catch (std::exception const& e)
 | 
			
		||||
    {
 | 
			
		||||
        JLOG(j_.error()) << "Exception during offer crossing: " << e.what();
 | 
			
		||||
        return {tecINTERNAL, taker.remaining_offer()};
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::pair<TER, Amounts>
 | 
			
		||||
CreateOffer::flowCross(
 | 
			
		||||
    PaymentSandbox& psb,
 | 
			
		||||
@@ -944,22 +890,11 @@ CreateOffer::cross(
 | 
			
		||||
    Amounts const& takerAmount,
 | 
			
		||||
    std::optional<uint256> const& domainID)
 | 
			
		||||
{
 | 
			
		||||
    if (sb.rules().enabled(featureFlowCross))
 | 
			
		||||
    {
 | 
			
		||||
        PaymentSandbox psbFlow{&sb};
 | 
			
		||||
        PaymentSandbox psbCancelFlow{&sbCancel};
 | 
			
		||||
        auto const ret =
 | 
			
		||||
            flowCross(psbFlow, psbCancelFlow, takerAmount, domainID);
 | 
			
		||||
        psbFlow.apply(sb);
 | 
			
		||||
        psbCancelFlow.apply(sbCancel);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Sandbox sbTaker{&sb};
 | 
			
		||||
    Sandbox sbCancelTaker{&sbCancel};
 | 
			
		||||
    auto const ret = takerCross(sbTaker, sbCancelTaker, takerAmount);
 | 
			
		||||
    sbTaker.apply(sb);
 | 
			
		||||
    sbCancelTaker.apply(sbCancel);
 | 
			
		||||
    PaymentSandbox psbFlow{&sb};
 | 
			
		||||
    PaymentSandbox psbCancelFlow{&sbCancel};
 | 
			
		||||
    auto const ret = flowCross(psbFlow, psbCancelFlow, takerAmount, domainID);
 | 
			
		||||
    psbFlow.apply(sb);
 | 
			
		||||
    psbCancelFlow.apply(sbCancel);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -109,13 +109,6 @@ private:
 | 
			
		||||
    bool
 | 
			
		||||
    reachedOfferCrossingLimit(Taker const& taker) const;
 | 
			
		||||
 | 
			
		||||
    // Fill offer as much as possible by consuming offers already on the books,
 | 
			
		||||
    // and adjusting account balances accordingly.
 | 
			
		||||
    //
 | 
			
		||||
    // Charges fees on top to taker.
 | 
			
		||||
    std::pair<TER, Amounts>
 | 
			
		||||
    takerCross(Sandbox& sb, Sandbox& sbCancel, Amounts const& takerAmount);
 | 
			
		||||
 | 
			
		||||
    // Use the payment flow code to perform offer crossing.
 | 
			
		||||
    std::pair<TER, Amounts>
 | 
			
		||||
    flowCross(
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user