From 7584a683ddd75444807e919c45334cba46e2d9ff Mon Sep 17 00:00:00 2001 From: Ayaz Salikhov Date: Tue, 17 Jun 2025 14:22:06 +0100 Subject: [PATCH] fix: Add domain to book_changes (#2229) Fix: https://github.com/XRPLF/clio/issues/2221 --- src/rpc/BookChangesHelper.hpp | 3 + tests/common/util/TestObject.cpp | 13 ++- tests/common/util/TestObject.hpp | 7 +- tests/unit/rpc/handlers/BookChangesTests.cpp | 106 +++++++++++++------ 4 files changed, 90 insertions(+), 39 deletions(-) diff --git a/src/rpc/BookChangesHelper.hpp b/src/rpc/BookChangesHelper.hpp index f802b076..ec419856 100644 --- a/src/rpc/BookChangesHelper.hpp +++ b/src/rpc/BookChangesHelper.hpp @@ -265,6 +265,9 @@ tag_invoke(boost::json::value_from_tag, boost::json::value& jv, BookChange const {JS(open), to_string(change.openRate.iou())}, {JS(close), to_string(change.closeRate.iou())}, }; + + if (change.domain.has_value()) + jv.as_object()[JS(domain)] = ripple::to_string(*change.domain); } /** diff --git a/tests/common/util/TestObject.cpp b/tests/common/util/TestObject.cpp index 7d215202..4f10b593 100644 --- a/tests/common/util/TestObject.cpp +++ b/tests/common/util/TestObject.cpp @@ -328,18 +328,21 @@ createMetaDataForBookChange( std::string_view issueId, uint32_t transactionIndex, int finalTakerGets, - int perviousTakerGets, + int previousTakerGets, int finalTakerPays, - int perviousTakerPays + int previousTakerPays, + std::optional domain ) { ripple::STObject finalFields(ripple::sfFinalFields); ripple::Issue const issue1 = getIssue(currency, issueId); finalFields.setFieldAmount(ripple::sfTakerPays, ripple::STAmount(issue1, finalTakerPays)); finalFields.setFieldAmount(ripple::sfTakerGets, ripple::STAmount(finalTakerGets, false)); + if (domain.has_value()) + finalFields.setFieldH256(ripple::sfDomainID, ripple::uint256{*domain}); ripple::STObject previousFields(ripple::sfPreviousFields); - previousFields.setFieldAmount(ripple::sfTakerPays, ripple::STAmount(issue1, perviousTakerPays)); - previousFields.setFieldAmount(ripple::sfTakerGets, ripple::STAmount(perviousTakerGets, false)); + previousFields.setFieldAmount(ripple::sfTakerPays, ripple::STAmount(issue1, previousTakerPays)); + previousFields.setFieldAmount(ripple::sfTakerGets, ripple::STAmount(previousTakerGets, false)); ripple::STObject metaObj(ripple::sfTransactionMetaData); ripple::STArray metaArray{1}; ripple::STObject node(ripple::sfModifiedNode); @@ -484,7 +487,7 @@ createOfferLedgerObject( std::string_view getsIssueId, std::string_view paysIssueId, std::string_view dirId, - std::optional const& domain + std::optional domain ) { ripple::STObject offer(ripple::sfLedgerEntry); diff --git a/tests/common/util/TestObject.hpp b/tests/common/util/TestObject.hpp index 84c1cc97..3e4ba2f3 100644 --- a/tests/common/util/TestObject.hpp +++ b/tests/common/util/TestObject.hpp @@ -182,9 +182,10 @@ createMetaDataForBookChange( std::string_view issueId, uint32_t transactionIndex, int finalTakerGets, - int perviousTakerGets, + int previousTakerGets, int finalTakerPays, - int perviousTakerPays + int previousTakerPays, + std::optional domain = std::nullopt ); /* @@ -258,7 +259,7 @@ createOfferLedgerObject( std::string_view getsIssueId, std::string_view paysIssueId, std::string_view bookDirId, - std::optional const& domain = std::nullopt + std::optional domain = std::nullopt ); [[nodiscard]] ripple::STObject diff --git a/tests/unit/rpc/handlers/BookChangesTests.cpp b/tests/unit/rpc/handlers/BookChangesTests.cpp index 8006d2b8..c6fa2a70 100644 --- a/tests/unit/rpc/handlers/BookChangesTests.cpp +++ b/tests/unit/rpc/handlers/BookChangesTests.cpp @@ -50,6 +50,7 @@ constexpr auto kISSUER = "rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD"; constexpr auto kACCOUNT1 = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"; constexpr auto kACCOUNT2 = "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun"; constexpr auto kLEDGER_HASH = "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652"; +constexpr auto kDOMAIN = "F10D0CC9A0F9A3CBF585B80BE09A186483668FDBDD39AA7E3370F3649CE134E5"; constexpr auto kMAX_SEQ = 30; constexpr auto kMIN_SEQ = 10; @@ -79,19 +80,19 @@ generateTestValuesForParametersTest() return std::vector{ BookChangesParamTestCaseBundle{ .testName = "LedgerHashInvalid", - .testJson = R"JSON({"ledger_hash":"1"})JSON", + .testJson = R"JSON({"ledger_hash": "1"})JSON", .expectedError = "invalidParams", .expectedErrorMessage = "ledger_hashMalformed" }, BookChangesParamTestCaseBundle{ .testName = "LedgerHashNotString", - .testJson = R"JSON({"ledger_hash":1})JSON", + .testJson = R"JSON({"ledger_hash": 1})JSON", .expectedError = "invalidParams", .expectedErrorMessage = "ledger_hashNotString" }, BookChangesParamTestCaseBundle{ .testName = "LedgerIndexInvalid", - .testJson = R"JSON({"ledger_index":"a"})JSON", + .testJson = R"JSON({"ledger_index": "a"})JSON", .expectedError = "invalidParams", .expectedErrorMessage = "ledgerIndexMalformed" }, @@ -121,11 +122,11 @@ TEST_P(BookChangesParameterTest, InvalidParams) TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaIntSequence) { - EXPECT_CALL(*backend_, fetchLedgerBySequence).Times(1); + EXPECT_CALL(*backend_, fetchLedgerBySequence); // return empty ledgerHeader ON_CALL(*backend_, fetchLedgerBySequence(kMAX_SEQ, _)).WillByDefault(Return(std::optional{})); - auto static const kINPUT = json::parse(R"JSON({"ledger_index":30})JSON"); + static auto const kINPUT = json::parse(R"JSON({"ledger_index": 30})JSON"); auto const handler = AnyHandler{BookChangesHandler{backend_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); @@ -138,11 +139,11 @@ TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaIntSequence) TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaStringSequence) { - EXPECT_CALL(*backend_, fetchLedgerBySequence).Times(1); + EXPECT_CALL(*backend_, fetchLedgerBySequence); // return empty ledgerHeader ON_CALL(*backend_, fetchLedgerBySequence(kMAX_SEQ, _)).WillByDefault(Return(std::nullopt)); - auto static const kINPUT = json::parse(R"JSON({"ledger_index":"30"})JSON"); + static auto const kINPUT = json::parse(R"JSON({"ledger_index": "30"})JSON"); auto const handler = AnyHandler{BookChangesHandler{backend_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); @@ -155,14 +156,13 @@ TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaStringSequence) TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaHash) { - EXPECT_CALL(*backend_, fetchLedgerByHash).Times(1); // return empty ledgerHeader - ON_CALL(*backend_, fetchLedgerByHash(ripple::uint256{kLEDGER_HASH}, _)) - .WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend_, fetchLedgerByHash(ripple::uint256{kLEDGER_HASH}, _)) + .WillOnce(Return(std::optional{})); - auto static const kINPUT = json::parse(fmt::format( + static auto const kINPUT = json::parse(fmt::format( R"JSON({{ - "ledger_hash":"{}" + "ledger_hash": "{}" }})JSON", kLEDGER_HASH )); @@ -180,28 +180,27 @@ TEST_F(RPCBookChangesHandlerTest, NormalPath) { static constexpr auto kEXPECTED_OUT = R"JSON({ - "type":"bookChanges", - "ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", - "ledger_index":30, - "ledger_time":0, - "validated":true, - "changes":[ + "type": "bookChanges", + "ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", + "ledger_index": 30, + "ledger_time": 0, + "validated": true, + "changes": [ { - "currency_a":"XRP_drops", - "currency_b":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD/0158415500000000C1F76FF6ECB0BAC600000000", - "volume_a":"2", - "volume_b":"2", - "high":"-1", - "low":"-1", - "open":"-1", - "close":"-1" + "currency_a": "XRP_drops", + "currency_b": "rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD/0158415500000000C1F76FF6ECB0BAC600000000", + "volume_a": "2", + "volume_b": "2", + "high": "-1", + "low": "-1", + "open": "-1", + "close": "-1" } ] })JSON"; - EXPECT_CALL(*backend_, fetchLedgerBySequence).Times(1); - ON_CALL(*backend_, fetchLedgerBySequence(kMAX_SEQ, _)) - .WillByDefault(Return(createLedgerHeader(kLEDGER_HASH, kMAX_SEQ))); + EXPECT_CALL(*backend_, fetchLedgerBySequence(kMAX_SEQ, _)) + .WillOnce(Return(createLedgerHeader(kLEDGER_HASH, kMAX_SEQ))); auto transactions = std::vector{}; auto trans1 = TransactionAndMetadata(); @@ -212,8 +211,53 @@ TEST_F(RPCBookChangesHandlerTest, NormalPath) trans1.metadata = metaObj.getSerializer().peekData(); transactions.push_back(trans1); - EXPECT_CALL(*backend_, fetchAllTransactionsInLedger).Times(1); - ON_CALL(*backend_, fetchAllTransactionsInLedger(kMAX_SEQ, _)).WillByDefault(Return(transactions)); + EXPECT_CALL(*backend_, fetchAllTransactionsInLedger(kMAX_SEQ, _)).WillOnce(Return(transactions)); + + auto const handler = AnyHandler{BookChangesHandler{backend_}}; + runSpawn([&](auto yield) { + auto const output = handler.process(json::parse("{}"), Context{yield}); + ASSERT_TRUE(output); + EXPECT_EQ(*output.result, json::parse(kEXPECTED_OUT)); + }); +} + +TEST_F(RPCBookChangesHandlerTest, NormalPathWithDomain) +{ + static constexpr auto kEXPECTED_OUT = + R"JSON({ + "type": "bookChanges", + "ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", + "ledger_index": 30, + "ledger_time": 0, + "validated": true, + "changes": [ + { + "currency_a": "XRP_drops", + "currency_b": "rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD/0158415500000000C1F76FF6ECB0BAC600000000", + "volume_a": "2", + "volume_b": "2", + "high": "-1", + "low": "-1", + "open": "-1", + "close": "-1", + "domain": "F10D0CC9A0F9A3CBF585B80BE09A186483668FDBDD39AA7E3370F3649CE134E5" + } + ] + })JSON"; + + EXPECT_CALL(*backend_, fetchLedgerBySequence(kMAX_SEQ, _)) + .WillOnce(Return(createLedgerHeader(kLEDGER_HASH, kMAX_SEQ))); + + auto transactions = std::vector{}; + auto trans1 = TransactionAndMetadata(); + ripple::STObject const obj = createPaymentTransactionObject(kACCOUNT1, kACCOUNT2, 1, 1, 32); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + ripple::STObject const metaObj = createMetaDataForBookChange(kCURRENCY, kISSUER, 22, 1, 3, 3, 1, kDOMAIN); + trans1.metadata = metaObj.getSerializer().peekData(); + transactions.push_back(trans1); + + EXPECT_CALL(*backend_, fetchAllTransactionsInLedger(kMAX_SEQ, _)).WillOnce(Return(transactions)); auto const handler = AnyHandler{BookChangesHandler{backend_}}; runSpawn([&](auto yield) {