diff --git a/CMake/Settings.cmake b/CMake/Settings.cmake index bab9ff1e..54f050b4 100644 --- a/CMake/Settings.cmake +++ b/CMake/Settings.cmake @@ -19,7 +19,7 @@ set(COMPILER_FLAGS -Wunused ) -if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT lint) +if (is_gcc AND NOT lint) list(APPEND COMPILER_FLAGS -Wduplicated-branches -Wduplicated-cond @@ -28,12 +28,18 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT lint) ) endif () -if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") +if (is_clang) list(APPEND COMPILER_FLAGS -Wshadow # gcc is to aggressive with shadowing https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78147 ) endif () +if (is_appleclang) + list(APPEND COMPILER_FLAGS + -Wreorder-init-list + ) +endif () + # See https://github.com/cpp-best-practices/cppbestpractices/blob/master/02-Use_the_Tools_Available.md#gcc--clang for the flags description target_compile_options (clio PUBLIC ${COMPILER_FLAGS}) diff --git a/src/rpc/handlers/AccountTx.cpp b/src/rpc/handlers/AccountTx.cpp index 88a27517..2757241f 100644 --- a/src/rpc/handlers/AccountTx.cpp +++ b/src/rpc/handlers/AccountTx.cpp @@ -184,14 +184,20 @@ AccountTxHandler::process(AccountTxHandler::Input input, Context const& ctx) con continue; } - obj[JS(tx)].as_object()[JS(ledger_index)] = txnPlusMeta.ledgerSequence; obj[JS(tx)].as_object()[JS(date)] = txnPlusMeta.date; + obj[JS(tx)].as_object()[JS(ledger_index)] = txnPlusMeta.ledgerSequence; + + if (ctx.apiVersion < 2u) + obj[JS(tx)].as_object()[JS(inLedger)] = txnPlusMeta.ledgerSequence; } else { obj[JS(meta)] = ripple::strHex(txnPlusMeta.metadata); obj[JS(tx_blob)] = ripple::strHex(txnPlusMeta.transaction); obj[JS(ledger_index)] = txnPlusMeta.ledgerSequence; + + if (ctx.apiVersion < 2u) + obj[JS(inLedger)] = txnPlusMeta.ledgerSequence; } obj[JS(validated)] = true; diff --git a/src/rpc/handlers/Tx.cpp b/src/rpc/handlers/Tx.cpp index b49300af..c14ef5f0 100644 --- a/src/rpc/handlers/Tx.cpp +++ b/src/rpc/handlers/Tx.cpp @@ -36,7 +36,7 @@ TxHandler::process(Input input, Context const& ctx) const return Error{Status{RippledError::rpcEXCESSIVE_LGR_RANGE}}; } - auto output = TxHandler::Output{}; + auto output = TxHandler::Output{.apiVersion = ctx.apiVersion}; auto const dbResponse = sharedPtrBackend_->fetchTransaction(ripple::uint256{std::string_view(input.transaction)}, ctx.yield); @@ -55,7 +55,6 @@ TxHandler::process(Input input, Context const& ctx) const return Error{Status{RippledError::rpcTXN_NOT_FOUND}}; } - // clio does not implement 'inLedger' which is a deprecated field if (!input.binary) { auto const [txn, meta] = toExpandedJson(*dbResponse, NFTokenjson::ENABLE); @@ -95,6 +94,9 @@ tag_invoke(boost::json::value_from_tag, boost::json::value& jv, TxHandler::Outpu obj[JS(date)] = output.date; obj[JS(ledger_index)] = output.ledgerIndex; + if (output.apiVersion < 2u) + obj[JS(inLedger)] = output.ledgerIndex; + jv = std::move(obj); } diff --git a/src/rpc/handlers/Tx.h b/src/rpc/handlers/Tx.h index 39dcdc93..37ff3142 100644 --- a/src/rpc/handlers/Tx.h +++ b/src/rpc/handlers/Tx.h @@ -38,13 +38,14 @@ class TxHandler public: struct Output { - uint32_t date; - std::string hash; - uint32_t ledgerIndex; - std::optional meta; - std::optional tx; - std::optional metaStr; - std::optional txStr; + uint32_t date = 0u; + std::string hash{}; + uint32_t ledgerIndex = 0u; + std::optional meta{}; + std::optional tx{}; + std::optional metaStr{}; + std::optional txStr{}; + uint32_t apiVersion = 0u; bool validated = true; }; diff --git a/unittests/rpc/handlers/AccountTxTests.cpp b/unittests/rpc/handlers/AccountTxTests.cpp index 7083e590..4a6203b3 100644 --- a/unittests/rpc/handlers/AccountTxTests.cpp +++ b/unittests/rpc/handlers/AccountTxTests.cpp @@ -47,7 +47,7 @@ struct AccountTxParamTestCaseBundle std::string testJson; std::optional expectedError; std::optional expectedErrorMessage; - std::uint32_t apiVersion = 2; + std::uint32_t apiVersion = 2u; }; // parameterized test cases for parameters check @@ -355,9 +355,7 @@ TEST_P(AccountTxParameterTest, CheckParams) auto const testBundle = GetParam(); auto* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); ASSERT_NE(rawBackendPtr, nullptr); - std::cout << "Before parse" << std::endl; auto const req = json::parse(testBundle.testJson); - std::cout << "After parse" << std::endl; if (testBundle.expectedError.has_value()) { ASSERT_TRUE(testBundle.expectedErrorMessage.has_value()); @@ -976,200 +974,204 @@ TEST_F(RPCAccountTxHandlerTest, TxLargerThanMaxSeq) }); } -TEST_F(RPCAccountTxHandlerTest, NFTTxs) +TEST_F(RPCAccountTxHandlerTest, NFTTxs_API_v1) { auto const OUT = R"({ - "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", - "ledger_index_min": 10, - "ledger_index_max": 30, - "transactions": [ + "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "ledger_index_min": 10, + "ledger_index_max": 30, + "transactions": [ + { + "meta": { + "AffectedNodes": + [ + { + "ModifiedNode": { - "meta": { - "AffectedNodes": + "FinalFields": + { + "NFTokens": [ { - "ModifiedNode": + "NFToken": { - "FinalFields": - { - "NFTokens": - [ - { - "NFToken": - { - "NFTokenID": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF", - "URI": "7465737475726C" - } - }, - { - "NFToken": - { - "NFTokenID": "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", - "URI": "7465737475726C" - } - } - ] - }, - "LedgerEntryType": "NFTokenPage", - "PreviousFields": - { - "NFTokens": - [ - { - "NFToken": - { - "NFTokenID": "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", - "URI": "7465737475726C" - } - } - ] - } - } - } - ], - "TransactionIndex": 0, - "TransactionResult": "tesSUCCESS", - "nftoken_id": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF" - }, - "tx": - { - "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", - "Fee": "50", - "NFTokenTaxon": 123, - "Sequence": 1, - "SigningPubKey": "74657374", - "TransactionType": "NFTokenMint", - "hash": "C74463F49CFDCBEF3E9902672719918CDE5042DC7E7660BEBD1D1105C4B6DFF4", - "ledger_index": 11, - "date": 1 - }, - "validated": true - }, - { - "meta": - { - "AffectedNodes": - [ - { - "DeletedNode": - { - "FinalFields": - { - "NFTokenID": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA" - }, - "LedgerEntryType": "NFTokenOffer" - } - } - ], - "TransactionIndex": 0, - "TransactionResult": "tesSUCCESS", - "nftoken_id": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA" - }, - "tx": - { - "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", - "Fee": "50", - "NFTokenBuyOffer": "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", - "Sequence": 1, - "SigningPubKey": "74657374", - "TransactionType": "NFTokenAcceptOffer", - "hash": "7682BE6BCDE62F8142915DD852936623B68FC3839A8A424A6064B898702B0CDF", - "ledger_index": 11, - "date": 2 - }, - "validated": true - }, - { - "meta": - { - "AffectedNodes": - [ - { - "DeletedNode": { - "FinalFields": - { - "NFTokenID": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA" - }, - "LedgerEntryType": "NFTokenOffer" + "NFTokenID": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF", + "URI": "7465737475726C" } }, { - "DeletedNode": + "NFToken": { - "FinalFields": - { - "NFTokenID": "15FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF" - }, - "LedgerEntryType": "NFTokenOffer" + "NFTokenID": "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "URI": "7465737475726C" } } - ], - "TransactionIndex": 0, - "TransactionResult": "tesSUCCESS", - "nftoken_ids": - [ - "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA", - "15FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF" ] }, - "tx": + "LedgerEntryType": "NFTokenPage", + "PreviousFields": { - "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", - "Fee": "50", - "NFTokenOffers": - [ - "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA", - "15FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF" - ], - "Sequence": 1, - "SigningPubKey": "74657374", - "TransactionType": "NFTokenCancelOffer", - "hash": "9F82743EEB30065FB9CB92C61F0F064B5859C5A590FA811FAAAD9C988E5B47DB", - "ledger_index": 11, - "date": 3 - }, - "validated": true - }, - { - "meta": - { - "AffectedNodes": + "NFTokens": [ { - "CreatedNode": + "NFToken": { - "LedgerEntryType": "NFTokenOffer", - "LedgerIndex": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA" + "NFTokenID": "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "URI": "7465737475726C" } } - ], - "TransactionIndex": 0, - "TransactionResult": "tesSUCCESS", - "offer_id": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA" - }, - "tx": - { - "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", - "Amount": "123", - "Fee": "50", - "NFTokenID": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF", - "Sequence": 1, - "SigningPubKey": "74657374", - "TransactionType": "NFTokenCreateOffer", - "hash": "ECB1837EB7C7C0AC22ECDCCE59FDD4795C70E0B9D8F4E1C9A9408BB7EC75DA5C", - "ledger_index": 11, - "date": 4 - }, - "validated": true + ] + } } - ], - "validated": true, - "marker": - { - "ledger": 12, - "seq": 34 } - })"; + ], + "TransactionIndex": 0, + "TransactionResult": "tesSUCCESS", + "nftoken_id": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF" + }, + "tx": + { + "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Fee": "50", + "NFTokenTaxon": 123, + "Sequence": 1, + "SigningPubKey": "74657374", + "TransactionType": "NFTokenMint", + "hash": "C74463F49CFDCBEF3E9902672719918CDE5042DC7E7660BEBD1D1105C4B6DFF4", + "ledger_index": 11, + "inLedger": 11, + "date": 1 + }, + "validated": true + }, + { + "meta": + { + "AffectedNodes": + [ + { + "DeletedNode": + { + "FinalFields": + { + "NFTokenID": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA" + }, + "LedgerEntryType": "NFTokenOffer" + } + } + ], + "TransactionIndex": 0, + "TransactionResult": "tesSUCCESS", + "nftoken_id": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA" + }, + "tx": + { + "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Fee": "50", + "NFTokenBuyOffer": "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "Sequence": 1, + "SigningPubKey": "74657374", + "TransactionType": "NFTokenAcceptOffer", + "hash": "7682BE6BCDE62F8142915DD852936623B68FC3839A8A424A6064B898702B0CDF", + "ledger_index": 11, + "inLedger": 11, + "date": 2 + }, + "validated": true + }, + { + "meta": + { + "AffectedNodes": + [ + { + "DeletedNode": { + "FinalFields": + { + "NFTokenID": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA" + }, + "LedgerEntryType": "NFTokenOffer" + } + }, + { + "DeletedNode": + { + "FinalFields": + { + "NFTokenID": "15FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF" + }, + "LedgerEntryType": "NFTokenOffer" + } + } + ], + "TransactionIndex": 0, + "TransactionResult": "tesSUCCESS", + "nftoken_ids": + [ + "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA", + "15FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF" + ] + }, + "tx": + { + "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Fee": "50", + "NFTokenOffers": + [ + "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA", + "15FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF" + ], + "Sequence": 1, + "SigningPubKey": "74657374", + "TransactionType": "NFTokenCancelOffer", + "hash": "9F82743EEB30065FB9CB92C61F0F064B5859C5A590FA811FAAAD9C988E5B47DB", + "ledger_index": 11, + "inLedger": 11, + "date": 3 + }, + "validated": true + }, + { + "meta": + { + "AffectedNodes": + [ + { + "CreatedNode": + { + "LedgerEntryType": "NFTokenOffer", + "LedgerIndex": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA" + } + } + ], + "TransactionIndex": 0, + "TransactionResult": "tesSUCCESS", + "offer_id": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA" + }, + "tx": + { + "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Amount": "123", + "Fee": "50", + "NFTokenID": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF", + "Sequence": 1, + "SigningPubKey": "74657374", + "TransactionType": "NFTokenCreateOffer", + "hash": "ECB1837EB7C7C0AC22ECDCCE59FDD4795C70E0B9D8F4E1C9A9408BB7EC75DA5C", + "ledger_index": 11, + "inLedger": 11, + "date": 4 + }, + "validated": true + } + ], + "validated": true, + "marker": + { + "ledger": 12, + "seq": 34 + } + })"; mockBackendPtr->updateRange(MINSEQ); // min mockBackendPtr->updateRange(MAXSEQ); // max MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); @@ -1196,7 +1198,233 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs) ACCOUNT, -1, -1)); - auto const output = handler.process(input, Context{yield}); + auto const output = handler.process(input, Context{.yield = yield, .apiVersion = 1u}); + ASSERT_TRUE(output); + EXPECT_EQ(*output, json::parse(OUT)); + }); +} + +TEST_F(RPCAccountTxHandlerTest, NFTTxs_API_v2) +{ + auto const OUT = R"({ + "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "ledger_index_min": 10, + "ledger_index_max": 30, + "transactions": [ + { + "meta": { + "AffectedNodes": + [ + { + "ModifiedNode": + { + "FinalFields": + { + "NFTokens": + [ + { + "NFToken": + { + "NFTokenID": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF", + "URI": "7465737475726C" + } + }, + { + "NFToken": + { + "NFTokenID": "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "URI": "7465737475726C" + } + } + ] + }, + "LedgerEntryType": "NFTokenPage", + "PreviousFields": + { + "NFTokens": + [ + { + "NFToken": + { + "NFTokenID": "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "URI": "7465737475726C" + } + } + ] + } + } + } + ], + "TransactionIndex": 0, + "TransactionResult": "tesSUCCESS", + "nftoken_id": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF" + }, + "tx": + { + "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Fee": "50", + "NFTokenTaxon": 123, + "Sequence": 1, + "SigningPubKey": "74657374", + "TransactionType": "NFTokenMint", + "hash": "C74463F49CFDCBEF3E9902672719918CDE5042DC7E7660BEBD1D1105C4B6DFF4", + "ledger_index": 11, + "date": 1 + }, + "validated": true + }, + { + "meta": + { + "AffectedNodes": + [ + { + "DeletedNode": + { + "FinalFields": + { + "NFTokenID": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA" + }, + "LedgerEntryType": "NFTokenOffer" + } + } + ], + "TransactionIndex": 0, + "TransactionResult": "tesSUCCESS", + "nftoken_id": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA" + }, + "tx": + { + "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Fee": "50", + "NFTokenBuyOffer": "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "Sequence": 1, + "SigningPubKey": "74657374", + "TransactionType": "NFTokenAcceptOffer", + "hash": "7682BE6BCDE62F8142915DD852936623B68FC3839A8A424A6064B898702B0CDF", + "ledger_index": 11, + "date": 2 + }, + "validated": true + }, + { + "meta": + { + "AffectedNodes": + [ + { + "DeletedNode": { + "FinalFields": + { + "NFTokenID": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA" + }, + "LedgerEntryType": "NFTokenOffer" + } + }, + { + "DeletedNode": + { + "FinalFields": + { + "NFTokenID": "15FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF" + }, + "LedgerEntryType": "NFTokenOffer" + } + } + ], + "TransactionIndex": 0, + "TransactionResult": "tesSUCCESS", + "nftoken_ids": + [ + "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA", + "15FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF" + ] + }, + "tx": + { + "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Fee": "50", + "NFTokenOffers": + [ + "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA", + "15FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF" + ], + "Sequence": 1, + "SigningPubKey": "74657374", + "TransactionType": "NFTokenCancelOffer", + "hash": "9F82743EEB30065FB9CB92C61F0F064B5859C5A590FA811FAAAD9C988E5B47DB", + "ledger_index": 11, + "date": 3 + }, + "validated": true + }, + { + "meta": + { + "AffectedNodes": + [ + { + "CreatedNode": + { + "LedgerEntryType": "NFTokenOffer", + "LedgerIndex": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA" + } + } + ], + "TransactionIndex": 0, + "TransactionResult": "tesSUCCESS", + "offer_id": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA" + }, + "tx": + { + "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Amount": "123", + "Fee": "50", + "NFTokenID": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF", + "Sequence": 1, + "SigningPubKey": "74657374", + "TransactionType": "NFTokenCreateOffer", + "hash": "ECB1837EB7C7C0AC22ECDCCE59FDD4795C70E0B9D8F4E1C9A9408BB7EC75DA5C", + "ledger_index": 11, + "date": 4 + }, + "validated": true + } + ], + "validated": true, + "marker": + { + "ledger": 12, + "seq": 34 + } + })"; + mockBackendPtr->updateRange(MINSEQ); // min + mockBackendPtr->updateRange(MAXSEQ); // max + MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); + ASSERT_NE(rawBackendPtr, nullptr); + auto const transactions = genNFTTransactions(MINSEQ + 1); + auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; + ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor)); + EXPECT_CALL( + *rawBackendPtr, + fetchAccountTransactions( + testing::_, testing::_, false, testing::Optional(testing::Eq(TransactionsCursor{10, 11})), testing::_)) + .Times(1); + + runSpawn([&, this](auto yield) { + auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const static input = json::parse(fmt::format( + R"({{ + "account": "{}", + "ledger_index_min": {}, + "ledger_index_max": {}, + "forward": false, + "marker": {{"ledger": 10, "seq": 11}} + }})", + ACCOUNT, + -1, + -1)); + auto const output = handler.process(input, Context{.yield = yield, .apiVersion = 2u}); ASSERT_TRUE(output); EXPECT_EQ(*output, json::parse(OUT)); }); @@ -1207,6 +1435,7 @@ struct AccountTxTransactionBundle std::string testName; std::string testJson; std::string result; + std::uint32_t apiVersion = 2u; }; // parameterized test cases for parameters check @@ -1366,7 +1595,57 @@ generateTransactionTypeTestValues() })", "[]"}, AccountTxTransactionBundle{ - "Payment", + "Payment_API_v1", + R"({ + "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "ledger_index": "validated", + "tx_type": "Payment" + })", + R"([ + { + "meta": { + "AffectedNodes": [ + { + "ModifiedNode": { + "FinalFields": { + "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Balance": "22" + }, + "LedgerEntryType": "AccountRoot" + } + }, + { + "ModifiedNode": { + "FinalFields": { + "Account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", + "Balance": "23" + }, + "LedgerEntryType": "AccountRoot" + } + }], + "TransactionIndex": 0, + "TransactionResult": "tesSUCCESS", + "delivered_amount": "unavailable" + }, + "tx": { + "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Amount": "1", + "Destination": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", + "Fee": "1", + "Sequence": 32, + "SigningPubKey": "74657374", + "TransactionType": "Payment", + "hash": "51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2", + "ledger_index": 30, + "inLedger": 30, + "date": 1 + }, + "validated": true + } + ])", + 1u}, + AccountTxTransactionBundle{ + "Payment_API_v2", R"({ "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "ledger_index": "validated", @@ -1412,7 +1691,8 @@ generateTransactionTypeTestValues() }, "validated": true } - ])"}, + ])", + 2u}, AccountTxTransactionBundle{ "PaymentChannelClaim", R"({ @@ -1500,7 +1780,7 @@ TEST_P(AccountTxTransactionTypeTest, SpecificTransactionType) runSpawn([&, this](auto yield) { auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; auto const req = json::parse(testBundle.testJson); - auto const output = handler.process(req, Context{yield}); + auto const output = handler.process(req, Context{.yield = yield, .apiVersion = testBundle.apiVersion}); EXPECT_TRUE(output); auto const transactions = output->at("transactions").as_array(); diff --git a/unittests/rpc/handlers/TxTests.cpp b/unittests/rpc/handlers/TxTests.cpp index 91030cc1..0e95e9a6 100644 --- a/unittests/rpc/handlers/TxTests.cpp +++ b/unittests/rpc/handlers/TxTests.cpp @@ -28,12 +28,49 @@ using namespace rpc; namespace json = boost::json; using namespace testing; -constexpr static auto TXNID = "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DD"; -constexpr static auto NFTID = "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF"; -constexpr static auto NFTID2 = "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA"; -constexpr static auto ACCOUNT = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"; -constexpr static auto ACCOUNT2 = "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun"; -constexpr static auto CURRENCY = "0158415500000000C1F76FF6ECB0BAC600000000"; +auto constexpr static TXNID = "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DD"; +auto constexpr static NFTID = "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF"; +auto constexpr static NFTID2 = "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA"; +auto constexpr static ACCOUNT = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"; +auto constexpr static ACCOUNT2 = "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun"; +auto constexpr static CURRENCY = "0158415500000000C1F76FF6ECB0BAC600000000"; + +auto constexpr static DEFAULT_OUT = R"({ + "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Fee": "2", + "Sequence": 100, + "SigningPubKey": "74657374", + "TakerGets": { + "currency": "0158415500000000C1F76FF6ECB0BAC600000000", + "issuer": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", + "value": "200" + }, + "TakerPays": "300", + "TransactionType": "OfferCreate", + "hash": "2E2FBAAFF767227FE4381C4BE9855986A6B9F96C62F6E443731AB36F7BBB8A08", + "meta": { + "AffectedNodes": [ + { + "CreatedNode": { + "LedgerEntryType": "Offer", + "NewFields": { + "TakerGets": "200", + "TakerPays": { + "currency": "0158415500000000C1F76FF6ECB0BAC600000000", + "issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "value": "300" + } + } + } + } + ], + "TransactionIndex": 100, + "TransactionResult": "tesSUCCESS" + }, + "date": 123456, + "ledger_index": 100, + "validated": true +})"; class RPCTxTest : public HandlerBaseTest { @@ -48,8 +85,8 @@ TEST_F(RPCTxTest, ExcessiveLgrRange) "command": "tx", "transaction": "{}", "min_ledger": 1, - "max_ledger":1002 - }})", + "max_ledger": 1002 + }})", TXNID)); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -70,7 +107,7 @@ TEST_F(RPCTxTest, InvalidLgrRange) "transaction": "{}", "max_ledger": 1, "min_ledger": 10 - }})", + }})", TXNID)); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -94,7 +131,7 @@ TEST_F(RPCTxTest, TxnNotFound) R"({{ "command": "tx", "transaction": "{}" - }})", + }})", TXNID)); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -121,8 +158,8 @@ TEST_F(RPCTxTest, TxnNotFoundInGivenRangeSearchAllFalse) "command": "tx", "transaction": "{}", "min_ledger": 1, - "max_ledger":1000 - }})", + "max_ledger": 1000 + }})", TXNID)); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -150,8 +187,8 @@ TEST_F(RPCTxTest, TxnNotFoundInGivenRangeSearchAllTrue) "command": "tx", "transaction": "{}", "min_ledger": 1, - "max_ledger":1000 - }})", + "max_ledger": 1000 + }})", TXNID)); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -163,76 +200,77 @@ TEST_F(RPCTxTest, TxnNotFoundInGivenRangeSearchAllTrue) }); } -TEST_F(RPCTxTest, DefaultParameter) +TEST_F(RPCTxTest, DefaultParameter_API_v1) { - auto constexpr static OUT = R"({ - "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", - "Fee":"2", - "Sequence":100, - "SigningPubKey":"74657374", - "TakerGets":{ - "currency":"0158415500000000C1F76FF6ECB0BAC600000000", - "issuer":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", - "value":"200" - }, - "TakerPays":"300", - "TransactionType":"OfferCreate", - "hash":"2E2FBAAFF767227FE4381C4BE9855986A6B9F96C62F6E443731AB36F7BBB8A08", - "meta":{ - "AffectedNodes":[ - { - "CreatedNode":{ - "LedgerEntryType":"Offer", - "NewFields":{ - "TakerGets":"200", - "TakerPays":{ - "currency":"0158415500000000C1F76FF6ECB0BAC600000000", - "issuer":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", - "value":"300" - } - } - } - } - ], - "TransactionIndex":100, - "TransactionResult":"tesSUCCESS" - }, - "date":123456, - "ledger_index":100, - "validated": true - })"; auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); ASSERT_NE(rawBackendPtr, nullptr); + TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 100, 200, 300).getSerializer().peekData(); tx.transaction = CreateCreateOfferTransactionObject(ACCOUNT, 2, 100, CURRENCY, ACCOUNT2, 200, 300).getSerializer().peekData(); tx.date = 123456; tx.ledgerSequence = 100; + ON_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillByDefault(Return(tx)); EXPECT_CALL(*rawBackendPtr, fetchTransaction).Times(1); + runSpawn([this](auto yield) { auto const handler = AnyHandler{TxHandler{mockBackendPtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", "transaction": "{}" - }})", + }})", TXNID)); - auto const output = handler.process(req, Context{yield}); + auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 1u}); ASSERT_TRUE(output); - EXPECT_EQ(*output, json::parse(OUT)); + + auto v1Output = json::parse(DEFAULT_OUT); + v1Output.as_object()[JS(inLedger)] = v1Output.as_object()[JS(ledger_index)]; + EXPECT_EQ(*output, v1Output); + }); +} + +TEST_F(RPCTxTest, DefaultParameter_API_v2) +{ + auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); + ASSERT_NE(rawBackendPtr, nullptr); + + TransactionAndMetadata tx; + tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 100, 200, 300).getSerializer().peekData(); + tx.transaction = + CreateCreateOfferTransactionObject(ACCOUNT, 2, 100, CURRENCY, ACCOUNT2, 200, 300).getSerializer().peekData(); + tx.date = 123456; + tx.ledgerSequence = 100; + + ON_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillByDefault(Return(tx)); + EXPECT_CALL(*rawBackendPtr, fetchTransaction).Times(1); + + runSpawn([this](auto yield) { + auto const handler = AnyHandler{TxHandler{mockBackendPtr}}; + auto const req = json::parse(fmt::format( + R"({{ + "command": "tx", + "transaction": "{}" + }})", + TXNID)); + auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 2u}); + ASSERT_TRUE(output); + EXPECT_EQ(*output, json::parse(DEFAULT_OUT)); }); } TEST_F(RPCTxTest, ReturnBinary) { + // Note: `inLedger` is API v1 only. See DefaultOutput_* auto constexpr static OUT = R"({ - "meta":"201C00000064F8E311006FE864D50AA87BEE5380000158415500000000C1F76FF6ECB0BAC6000000004B4E9C06F24296074F7BC48F92A97916C6DC5EA96540000000000000C8E1E1F1031000", - "tx":"120007240000006464400000000000012C65D5071AFD498D00000158415500000000C1F76FF6ECB0BAC600000000D31252CF902EF8DD8451243869B38667CBD89DF368400000000000000273047465737481144B4E9C06F24296074F7BC48F92A97916C6DC5EA9", - "hash":"05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DD", - "date":123456, - "ledger_index":100, + "meta": "201C00000064F8E311006FE864D50AA87BEE5380000158415500000000C1F76FF6ECB0BAC6000000004B4E9C06F24296074F7BC48F92A97916C6DC5EA96540000000000000C8E1E1F1031000", + "tx": "120007240000006464400000000000012C65D5071AFD498D00000158415500000000C1F76FF6ECB0BAC600000000D31252CF902EF8DD8451243869B38667CBD89DF368400000000000000273047465737481144B4E9C06F24296074F7BC48F92A97916C6DC5EA9", + "hash": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DD", + "date": 123456, + "ledger_index": 100, + "inLedger": 100, "validated": true })"; auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); @@ -252,7 +290,7 @@ TEST_F(RPCTxTest, ReturnBinary) "command": "tx", "transaction": "{}", "binary": true - }})", + }})", TXNID)); auto const output = handler.process(req, Context{yield}); ASSERT_TRUE(output); @@ -262,6 +300,7 @@ TEST_F(RPCTxTest, ReturnBinary) TEST_F(RPCTxTest, MintNFT) { + // Note: `inLedger` is API v1 only. See DefaultOutput_* auto const static OUT = fmt::format( R"({{ "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", @@ -312,9 +351,10 @@ TEST_F(RPCTxTest, MintNFT) "TransactionResult": "tesSUCCESS", "nftoken_id": "{}" }}, - "validated": true, "date": 123456, - "ledger_index": 100 + "ledger_index": 100, + "inLedger": 100, + "validated": true }})", NFTID, NFTID); @@ -381,7 +421,6 @@ TEST_F(RPCTxTest, NFTCancelOffer) }})", TXNID)); auto const output = handler.process(req, Context{yield}); - std::cout << "output: " << output.value() << std::endl; ASSERT_TRUE(output); for (auto const& id : output->at("meta").at("nftoken_ids").as_array()) @@ -394,7 +433,6 @@ TEST_F(RPCTxTest, NFTCancelOffer) EXPECT_TRUE(ids.empty()); }); - std::cout << "After spawn" << std::endl; } TEST_F(RPCTxTest, NFTCreateOffer)