From 6977cb892679c5851cfcfa161304bae710fcb4da Mon Sep 17 00:00:00 2001 From: Gregory Tsipenyuk Date: Sat, 6 Jun 2026 19:42:10 -0400 Subject: [PATCH] Fix missing else in PathRequest::parseJson --- src/test/app/Path_test.cpp | 62 ++++++++++++++++++++++++++-- src/xrpld/rpc/detail/PathRequest.cpp | 1 + 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/test/app/Path_test.cpp b/src/test/app/Path_test.cpp index 4cfe938798..fe264e910d 100644 --- a/src/test/app/Path_test.cpp +++ b/src/test/app/Path_test.cpp @@ -146,7 +146,8 @@ public: STAmount const& saDstAmount, std::optional const& saSendMax = std::nullopt, std::optional const& saSrcCurrency = std::nullopt, - std::optional const& domain = std::nullopt) + std::optional const& domain = std::nullopt, + std::optional const& saSrcIssuer = std::nullopt) { using namespace jtx; @@ -180,6 +181,10 @@ public: auto& sc = params[jss::source_currencies] = json::ValueType::Array; json::Value j = json::ValueType::Object; j[jss::currency] = to_string(saSrcCurrency.value()); + // Optional issuer for tests that need to exercise + // source_currencies entries more precisely than currency alone. + if (saSrcIssuer) + j[jss::issuer] = toBase58(*saSrcIssuer); sc.append(j); } if (domain) @@ -208,10 +213,11 @@ public: STAmount const& saDstAmount, std::optional const& saSendMax = std::nullopt, std::optional const& saSrcCurrency = std::nullopt, - std::optional const& domain = std::nullopt) + std::optional const& domain = std::nullopt, + std::optional const& saSrcIssuer = std::nullopt) { - json::Value result = - findPathsRequest(env, src, dst, saDstAmount, saSendMax, saSrcCurrency, domain); + json::Value result = findPathsRequest( + env, src, dst, saDstAmount, saSendMax, saSrcCurrency, domain, saSrcIssuer); BEAST_EXPECT(!result.isMember(jss::error)); STAmount da; @@ -324,6 +330,53 @@ public: BEAST_EXPECT(result.isMember(jss::error)); } + void + sourceCurrencyIssuerSelection() + { + testcase("source currency issuer selection"); + using namespace jtx; + + Env env = pathTestEnv(); + auto const alice = Account("alice"); + auto const bob = Account("bob"); + auto const gateway = Account("gateway"); + + env.fund(XRP(10000), alice, bob, gateway); + env.close(); + + auto const usd = gateway["USD"]; + env.trust(usd(600), alice); + env.trust(usd(700), bob); + env.trust(alice["USD"](700), bob); + env(pay(gateway, alice, usd(70))); + env(pay(gateway, bob, usd(50))); + env.close(); + + // Ask for USD from an explicit source issuer while send_max is + // Alice-issued USD. The parser should choose gateway-issued USD + // because gateway is the issuer in source_currencies. + // + // The Alice/Bob trust line is intentional: if Alice-issued USD is also + // considered as a source asset, pathfinding can produce an additional + // alternative. The single expected alternative below verifies that only + // the explicit issuer is selected. + auto const result = findPathsRequest( + env, + alice, + bob, + bob["USD"](-1), + alice["USD"](100).value(), + usd.currency, + std::nullopt, + gateway.id()); + auto const& alternatives = result[jss::alternatives]; + BEAST_EXPECT(alternatives.size() == 1); + auto const sa = amountFromJson(sfGeneric, alternatives[0u][jss::source_amount]); + auto const da = amountFromJson(sfGeneric, alternatives[0u][jss::destination_amount]); + BEAST_EXPECTS(equal(sa, usd(100)), sa.getFullText()); + BEAST_EXPECTS(equal(da, bob["USD"](100)), da.getFullText()); + } + void noDirectPathNoIntermediaryNoAlternatives() { @@ -1868,6 +1921,7 @@ public: run() override { sourceCurrenciesLimit(); + sourceCurrencyIssuerSelection(); noDirectPathNoIntermediaryNoAlternatives(); directPathNoIntermediary(); paymentAutoPathFind(); diff --git a/src/xrpld/rpc/detail/PathRequest.cpp b/src/xrpld/rpc/detail/PathRequest.cpp index 06507319f7..cd457f6633 100644 --- a/src/xrpld/rpc/detail/PathRequest.cpp +++ b/src/xrpld/rpc/detail/PathRequest.cpp @@ -438,6 +438,7 @@ PathRequest::parseJson(json::Value const& jvParams) { sciSourceAssets_.insert(Issue{currency, saSendMax_->getIssuer()}); } + else { sciSourceAssets_.insert(Issue{currency, *raSrcAccount_}); }