diff --git a/src/app/ClioApplication.cpp b/src/app/ClioApplication.cpp index bc5d0df1..d64a6b97 100644 --- a/src/app/ClioApplication.cpp +++ b/src/app/ClioApplication.cpp @@ -106,6 +106,8 @@ ClioApplication::run(bool const useNgWebServer) // Interface to the database auto backend = data::makeBackend(config_); + auto const amendmentCenter = std::make_shared(backend); + { auto const migrationInspector = migration::makeMigrationInspector(config_, backend); // Check if any migration is blocking Clio server starting. @@ -117,7 +119,7 @@ ClioApplication::run(bool const useNgWebServer) } // Manages clients subscribed to streams - auto subscriptions = feed::SubscriptionManager::makeSubscriptionManager(config_, backend); + auto subscriptions = feed::SubscriptionManager::makeSubscriptionManager(config_, backend, amendmentCenter); // Tracks which ledgers have been validated by the network auto ledgers = etl::NetworkValidatedLedgers::makeValidatedLedgers(); @@ -133,7 +135,7 @@ ClioApplication::run(bool const useNgWebServer) auto workQueue = rpc::WorkQueue::makeWorkQueue(config_); auto counters = rpc::Counters::makeCounters(workQueue); - auto const amendmentCenter = std::make_shared(backend); + auto const handlerProvider = std::make_shared( config_, backend, subscriptions, balancer, etl, amendmentCenter, counters ); diff --git a/src/data/AmendmentCenter.hpp b/src/data/AmendmentCenter.hpp index 777ba340..c080307e 100644 --- a/src/data/AmendmentCenter.hpp +++ b/src/data/AmendmentCenter.hpp @@ -134,6 +134,7 @@ struct Amendments { REGISTER(Credentials); REGISTER(DynamicNFT); REGISTER(PermissionedDomains); + REGISTER(fixFrozenLPTokenTransfer); // Obsolete but supported by libxrpl REGISTER(CryptoConditionsSuite); diff --git a/src/feed/SubscriptionManager.cpp b/src/feed/SubscriptionManager.cpp index 8c169be2..7db63718 100644 --- a/src/feed/SubscriptionManager.cpp +++ b/src/feed/SubscriptionManager.cpp @@ -191,7 +191,7 @@ SubscriptionManager::unsubBook(ripple::Book const& book, SubscriberSharedPtr con void SubscriptionManager::pubTransaction(data::TransactionAndMetadata const& txMeta, ripple::LedgerHeader const& lgrInfo) { - transactionFeed_.pub(txMeta, lgrInfo, backend_); + transactionFeed_.pub(txMeta, lgrInfo, backend_, amendmentCenter_); } boost::json::object diff --git a/src/feed/SubscriptionManager.hpp b/src/feed/SubscriptionManager.hpp index c51ea527..09c004a5 100644 --- a/src/feed/SubscriptionManager.hpp +++ b/src/feed/SubscriptionManager.hpp @@ -19,6 +19,7 @@ #pragma once +#include "data/AmendmentCenterInterface.hpp" #include "data/BackendInterface.hpp" #include "data/Types.hpp" #include "feed/SubscriptionManagerInterface.hpp" @@ -60,6 +61,7 @@ namespace feed { */ class SubscriptionManager : public SubscriptionManagerInterface { std::shared_ptr backend_; + std::shared_ptr amendmentCenter_; util::async::AnyExecutionContext ctx_; impl::ForwardFeed manifestFeed_; impl::ForwardFeed validationsFeed_; @@ -74,12 +76,14 @@ public: * * @param config The configuration to use * @param backend The backend to use + * @param amendmentCenter The amendmentCenter to use * @return A shared pointer to a new instance of SubscriptionManager */ static std::shared_ptr makeSubscriptionManager( util::config::ClioConfigDefinition const& config, - std::shared_ptr const& backend + std::shared_ptr const& backend, + std::shared_ptr const& amendmentCenter ) { auto const workersNum = config.get("subscription_workers"); @@ -87,7 +91,9 @@ public: util::Logger const logger{"Subscriptions"}; LOG(logger.info()) << "Starting subscription manager with " << workersNum << " workers"; - return std::make_shared(util::async::PoolExecutionContext(workersNum), backend); + return std::make_shared( + util::async::PoolExecutionContext(workersNum), backend, amendmentCenter + ); } /** @@ -95,12 +101,15 @@ public: * * @param executor The executor to use to publish the feeds * @param backend The backend to use + * @param amendmentCenter The amendmentCenter to use */ SubscriptionManager( util::async::AnyExecutionContext&& executor, - std::shared_ptr const& backend + std::shared_ptr const& backend, + std::shared_ptr const& amendmentCenter ) : backend_(backend) + , amendmentCenter_(amendmentCenter) , ctx_(std::move(executor)) , manifestFeed_(ctx_, "manifest") , validationsFeed_(ctx_, "validations") diff --git a/src/feed/impl/TransactionFeed.cpp b/src/feed/impl/TransactionFeed.cpp index 7ff0ba85..ac65cca6 100644 --- a/src/feed/impl/TransactionFeed.cpp +++ b/src/feed/impl/TransactionFeed.cpp @@ -19,6 +19,7 @@ #include "feed/impl/TransactionFeed.hpp" +#include "data/AmendmentCenterInterface.hpp" #include "data/BackendInterface.hpp" #include "data/Types.hpp" #include "feed/Types.hpp" @@ -174,7 +175,8 @@ void TransactionFeed::pub( data::TransactionAndMetadata const& txMeta, ripple::LedgerHeader const& lgrInfo, - std::shared_ptr const& backend + std::shared_ptr const& backend, + std::shared_ptr const& amendmentCenter ) { auto [tx, meta] = rpc::deserializeTxPlusMeta(txMeta, lgrInfo.seq); @@ -187,7 +189,7 @@ TransactionFeed::pub( if (account != amount.issue().account) { auto fetchFundsSynchronous = [&]() { data::synchronous([&](boost::asio::yield_context yield) { - ownerFunds = rpc::accountFunds(*backend, lgrInfo.seq, amount, account, yield); + ownerFunds = rpc::accountFunds(*backend, *amendmentCenter, lgrInfo.seq, amount, account, yield); }); }; data::retryOnTimeout(fetchFundsSynchronous); diff --git a/src/feed/impl/TransactionFeed.hpp b/src/feed/impl/TransactionFeed.hpp index 787fd761..856805bc 100644 --- a/src/feed/impl/TransactionFeed.hpp +++ b/src/feed/impl/TransactionFeed.hpp @@ -19,6 +19,7 @@ #pragma once +#include "data/AmendmentCenterInterface.hpp" #include "data/BackendInterface.hpp" #include "data/Types.hpp" #include "feed/Types.hpp" @@ -180,7 +181,8 @@ public: void pub(data::TransactionAndMetadata const& txMeta, ripple::LedgerHeader const& lgrInfo, - std::shared_ptr const& backend); + std::shared_ptr const& backend, + std::shared_ptr const& amendmentCenter); /** * @brief Get the number of subscribers of the transaction feed. diff --git a/src/rpc/AMMHelpers.cpp b/src/rpc/AMMHelpers.cpp index 2635530d..1a6dfe8b 100644 --- a/src/rpc/AMMHelpers.cpp +++ b/src/rpc/AMMHelpers.cpp @@ -38,6 +38,7 @@ namespace rpc { std::pair getAmmPoolHolds( BackendInterface const& backend, + data::AmendmentCenterInterface const& amendmentCenter, std::uint32_t sequence, ripple::AccountID const& ammAccountID, ripple::Issue const& issue1, @@ -46,10 +47,12 @@ getAmmPoolHolds( boost::asio::yield_context yield ) { - auto const assetInBalance = - accountHolds(backend, sequence, ammAccountID, issue1.currency, issue1.account, freezeHandling, yield); - auto const assetOutBalance = - accountHolds(backend, sequence, ammAccountID, issue2.currency, issue2.account, freezeHandling, yield); + auto const assetInBalance = accountHolds( + backend, amendmentCenter, sequence, ammAccountID, issue1.currency, issue1.account, freezeHandling, yield + ); + auto const assetOutBalance = accountHolds( + backend, amendmentCenter, sequence, ammAccountID, issue2.currency, issue2.account, freezeHandling, yield + ); return std::make_pair(assetInBalance, assetOutBalance); } @@ -65,7 +68,9 @@ getAmmLpHolds( ) { auto const lptCurrency = ammLPTCurrency(cur1, cur2); - return accountHolds(backend, sequence, lpAccount, lptCurrency, ammAccount, true, yield); + + // not using accountHolds because we don't need to check if the associated tokens of the LP are frozen + return ammAccountHolds(backend, sequence, lpAccount, lptCurrency, ammAccount, true, yield); } ripple::STAmount diff --git a/src/rpc/AMMHelpers.hpp b/src/rpc/AMMHelpers.hpp index 4af61dc8..286d3764 100644 --- a/src/rpc/AMMHelpers.hpp +++ b/src/rpc/AMMHelpers.hpp @@ -19,6 +19,7 @@ #pragma once +#include "data/AmendmentCenterInterface.hpp" #include "data/BackendInterface.hpp" #include @@ -37,6 +38,7 @@ namespace rpc { * @brief getAmmPoolHolds returns the balances of the amm asset pair * * @param backend The backend to use + * @param amendmentCenter The amendmentCenter to use * @param sequence The sequence number to use * @param ammAccountID The amm account * @param issue1 The first issue @@ -48,6 +50,7 @@ namespace rpc { std::pair getAmmPoolHolds( BackendInterface const& backend, + data::AmendmentCenterInterface const& amendmentCenter, std::uint32_t sequence, ripple::AccountID const& ammAccountID, ripple::Issue const& issue1, diff --git a/src/rpc/RPCHelpers.cpp b/src/rpc/RPCHelpers.cpp index 2294ecec..c5f24faa 100644 --- a/src/rpc/RPCHelpers.cpp +++ b/src/rpc/RPCHelpers.cpp @@ -19,12 +19,15 @@ #include "rpc/RPCHelpers.hpp" +#include "data/AmendmentCenter.hpp" +#include "data/AmendmentCenterInterface.hpp" #include "data/BackendInterface.hpp" #include "data/Types.hpp" #include "rpc/Errors.hpp" #include "rpc/JS.hpp" #include "rpc/common/Types.hpp" #include "util/AccountUtils.hpp" +#include "util/Assert.hpp" #include "util/Profiler.hpp" #include "util/log/Logger.hpp" #include "web/Context.hpp" @@ -943,6 +946,20 @@ isFrozen( return false; } +bool +isLPTokenFrozen( + BackendInterface const& backend, + std::uint32_t sequence, + ripple::AccountID const& account, + ripple::Issue const& asset, + ripple::Issue const& asset2, + boost::asio::yield_context yield +) +{ + return isFrozen(backend, sequence, account, asset.currency, asset.account, yield) || + isFrozen(backend, sequence, account, asset2.currency, asset2.account, yield); +} + ripple::XRPAmount xrpLiquid( BackendInterface const& backend, @@ -981,6 +998,7 @@ xrpLiquid( ripple::STAmount accountFunds( BackendInterface const& backend, + data::AmendmentCenterInterface const& amendmentCenter, std::uint32_t const sequence, ripple::STAmount const& amount, ripple::AccountID const& id, @@ -991,11 +1009,11 @@ accountFunds( return amount; } - return accountHolds(backend, sequence, id, amount.getCurrency(), amount.getIssuer(), true, yield); + return accountHolds(backend, amendmentCenter, sequence, id, amount.getCurrency(), amount.getIssuer(), true, yield); } ripple::STAmount -accountHolds( +ammAccountHolds( BackendInterface const& backend, std::uint32_t sequence, ripple::AccountID const& account, @@ -1006,6 +1024,7 @@ accountHolds( ) { ripple::STAmount amount; + ASSERT(!ripple::isXRP(currency), "LPToken currency can never be XRP"); if (ripple::isXRP(currency)) return {xrpLiquid(backend, sequence, account, yield)}; @@ -1036,6 +1055,91 @@ accountHolds( return amount; } +ripple::STAmount +accountHolds( + BackendInterface const& backend, + data::AmendmentCenterInterface const& amendmentCenter, + std::uint32_t sequence, + ripple::AccountID const& account, + ripple::Currency const& currency, + ripple::AccountID const& issuer, + bool const zeroIfFrozen, + boost::asio::yield_context yield +) +{ + ripple::STAmount amount; + if (ripple::isXRP(currency)) + return {xrpLiquid(backend, sequence, account, yield)}; + + auto const key = ripple::keylet::line(account, issuer, currency).key; + auto const blob = backend.fetchLedgerObject(key, sequence, yield); + + if (!blob) { + amount.setIssue(ripple::Issue(currency, issuer)); + amount.clear(); + return amount; + } + + auto const allowBalance = [&]() { + if (!zeroIfFrozen) + return true; + + if (isFrozen(backend, sequence, account, currency, issuer, yield)) + return false; + + if (amendmentCenter.isEnabled(yield, data::Amendments::fixFrozenLPTokenTransfer, sequence)) { + auto const issuerBlob = backend.fetchLedgerObject(ripple::keylet::account(issuer).key, sequence, yield); + + if (!issuerBlob) + return false; + + ripple::SLE const issuerSle{ + ripple::SerialIter{issuerBlob->data(), issuerBlob->size()}, ripple::keylet::account(issuer).key + }; + + // if the issuer is an amm account, then currency is lptoken, so we will need to check if the + // assets in the pool are frozen as well + if (issuerSle.isFieldPresent(ripple::sfAMMID)) { + auto const ammKeylet = ripple::keylet::amm(issuerSle[ripple::sfAMMID]); + auto const ammBlob = backend.fetchLedgerObject(ammKeylet.key, sequence, yield); + + if (!ammBlob) + return false; + + ripple::SLE const ammSle{ripple::SerialIter{ammBlob->data(), ammBlob->size()}, ammKeylet.key}; + + return !isLPTokenFrozen( + backend, + sequence, + account, + ammSle[ripple::sfAsset].get(), + ammSle[ripple::sfAsset2].get(), + yield + ); + } + } + + return true; + }(); + + if (allowBalance) { + ripple::SerialIter it{blob->data(), blob->size()}; + ripple::SLE const sle{it, key}; + + amount = sle.getFieldAmount(ripple::sfBalance); + if (account > issuer) { + // Put balance in account terms. + amount.negate(); + } + amount.setIssuer(issuer); + } else { + amount.setIssue(ripple::Issue(currency, issuer)); + amount.clear(); + } + + return amount; +} + ripple::Rate transferRate( BackendInterface const& backend, @@ -1064,6 +1168,7 @@ postProcessOrderBook( ripple::Book const& book, ripple::AccountID const& takerID, data::BackendInterface const& backend, + data::AmendmentCenterInterface const& amendmentCenter, std::uint32_t const ledgerSequence, boost::asio::yield_context yield ) @@ -1106,7 +1211,14 @@ postProcessOrderBook( firstOwnerOffer = false; } else { saOwnerFunds = accountHolds( - backend, ledgerSequence, uOfferOwnerID, book.out.currency, book.out.account, true, yield + backend, + amendmentCenter, + ledgerSequence, + uOfferOwnerID, + book.out.currency, + book.out.account, + true, + yield ); if (saOwnerFunds < beast::zero) diff --git a/src/rpc/RPCHelpers.hpp b/src/rpc/RPCHelpers.hpp index 0a9202d4..50d4d79a 100644 --- a/src/rpc/RPCHelpers.hpp +++ b/src/rpc/RPCHelpers.hpp @@ -24,6 +24,7 @@ * This file contains a variety of utility functions used when executing the handlers. */ +#include "data/AmendmentCenterInterface.hpp" #include "data/BackendInterface.hpp" #include "data/Types.hpp" #include "rpc/Errors.hpp" @@ -427,10 +428,32 @@ isFrozen( boost::asio::yield_context yield ); +/** + * @brief Whether the account that owns a LPToken is frozen for the assets in the pool + * + * @param backend The backend to use + * @param sequence The sequence + * @param account The account + * @param asset The first asset in the pool + * @param asset2 The second asset in the pool + * @param yield The coroutine context + * @return true if account is frozen for one of the assets + */ +bool +isLPTokenFrozen( + BackendInterface const& backend, + std::uint32_t sequence, + ripple::AccountID const& account, + ripple::Issue const& asset, + ripple::Issue const& asset2, + boost::asio::yield_context yield +); + /** * @brief Get the account funds * * @param backend The backend to use + * @param amendmentCenter The amendmentCenter to use * @param sequence The sequence * @param amount The amount * @param id The account ID @@ -440,6 +463,7 @@ isFrozen( ripple::STAmount accountFunds( BackendInterface const& backend, + data::AmendmentCenterInterface const& amendmentCenter, std::uint32_t sequence, ripple::STAmount const& amount, ripple::AccountID const& id, @@ -450,6 +474,7 @@ accountFunds( * @brief Get the amount that an account holds * * @param backend The backend to use + * @param amendmentCenter The amendmentCenter to use * @param sequence The sequence * @param account The account * @param currency The currency @@ -461,6 +486,7 @@ accountFunds( ripple::STAmount accountHolds( BackendInterface const& backend, + data::AmendmentCenterInterface const& amendmentCenter, std::uint32_t sequence, ripple::AccountID const& account, ripple::Currency const& currency, @@ -469,6 +495,29 @@ accountHolds( boost::asio::yield_context yield ); +/** + * @brief Get the amount that an LPToken owner holds + * + * @param backend The backend to use + * @param sequence The sequence + * @param account The account + * @param currency The currency + * @param issuer The issuer + * @param zeroIfFrozen Whether to return zero if frozen + * @param yield The coroutine context + * @return The amount account holds + */ +ripple::STAmount +ammAccountHolds( + BackendInterface const& backend, + std::uint32_t sequence, + ripple::AccountID const& account, + ripple::Currency const& currency, + ripple::AccountID const& issuer, + bool const zeroIfFrozen, + boost::asio::yield_context yield +); + /** * @brief Get the transfer rate * @@ -510,6 +559,7 @@ xrpLiquid( * @param book The book * @param takerID The taker ID * @param backend The backend to use + * @param amendmentCenter The amendmentCenter to use * @param ledgerSequence The ledger sequence * @param yield The coroutine context * @return The post processed order book @@ -520,6 +570,7 @@ postProcessOrderBook( ripple::Book const& book, ripple::AccountID const& takerID, data::BackendInterface const& backend, + data::AmendmentCenterInterface const& amendmentCenter, std::uint32_t ledgerSequence, boost::asio::yield_context yield ); diff --git a/src/rpc/common/impl/HandlerProvider.cpp b/src/rpc/common/impl/HandlerProvider.cpp index 90ec3f7b..cf4485cc 100644 --- a/src/rpc/common/impl/HandlerProvider.cpp +++ b/src/rpc/common/impl/HandlerProvider.cpp @@ -86,14 +86,14 @@ ProductionHandlerProvider::ProductionHandlerProvider( {"account_objects", {.handler = AccountObjectsHandler{backend}}}, {"account_offers", {.handler = AccountOffersHandler{backend}}}, {"account_tx", {.handler = AccountTxHandler{backend}}}, - {"amm_info", {.handler = AMMInfoHandler{backend}}}, + {"amm_info", {.handler = AMMInfoHandler{backend, amendmentCenter}}}, {"book_changes", {.handler = BookChangesHandler{backend}}}, - {"book_offers", {.handler = BookOffersHandler{backend}}}, + {"book_offers", {.handler = BookOffersHandler{backend, amendmentCenter}}}, {"deposit_authorized", {.handler = DepositAuthorizedHandler{backend}}}, {"feature", {.handler = FeatureHandler{backend, amendmentCenter}}}, {"gateway_balances", {.handler = GatewayBalancesHandler{backend}}}, {"get_aggregate_price", {.handler = GetAggregatePriceHandler{backend}}}, - {"ledger", {.handler = LedgerHandler{backend}}}, + {"ledger", {.handler = LedgerHandler{backend, amendmentCenter}}}, {"ledger_data", {.handler = LedgerDataHandler{backend}}}, {"ledger_entry", {.handler = LedgerEntryHandler{backend}}}, {"ledger_index", {.handler = LedgerIndexHandler{backend}, .isClioOnly = true}}, // clio only @@ -110,7 +110,7 @@ ProductionHandlerProvider::ProductionHandlerProvider( {"server_info", {.handler = ServerInfoHandler{backend, subscriptionManager, balancer, etl, counters}}}, {"transaction_entry", {.handler = TransactionEntryHandler{backend}}}, {"tx", {.handler = TxHandler{backend, etl}}}, - {"subscribe", {.handler = SubscribeHandler{backend, subscriptionManager}}}, + {"subscribe", {.handler = SubscribeHandler{backend, amendmentCenter, subscriptionManager}}}, {"unsubscribe", {.handler = UnsubscribeHandler{subscriptionManager}}}, {"version", {.handler = VersionHandler{config}}}, } diff --git a/src/rpc/handlers/AMMInfo.cpp b/src/rpc/handlers/AMMInfo.cpp index 93ed4924..e73c76b2 100644 --- a/src/rpc/handlers/AMMInfo.cpp +++ b/src/rpc/handlers/AMMInfo.cpp @@ -149,8 +149,9 @@ AMMInfoHandler::process(AMMInfoHandler::Input input, Context const& ctx) const issue2 = amm[sfAsset2].get(); } - auto const [asset1Balance, asset2Balance] = - getAmmPoolHolds(*sharedPtrBackend_, lgrInfo.seq, ammAccountID, issue1, issue2, false, ctx.yield); + auto const [asset1Balance, asset2Balance] = getAmmPoolHolds( + *sharedPtrBackend_, *amendmentCenter_, lgrInfo.seq, ammAccountID, issue1, issue2, false, ctx.yield + ); auto const lptAMMBalance = input.accountID ? getAmmLpHolds(*sharedPtrBackend_, lgrInfo.seq, amm, *input.accountID, ctx.yield) : amm[sfLPTokenBalance]; diff --git a/src/rpc/handlers/AMMInfo.hpp b/src/rpc/handlers/AMMInfo.hpp index 06b1236b..25cee74d 100644 --- a/src/rpc/handlers/AMMInfo.hpp +++ b/src/rpc/handlers/AMMInfo.hpp @@ -19,6 +19,7 @@ #pragma once +#include "data/AmendmentCenterInterface.hpp" #include "data/BackendInterface.hpp" #include "rpc/common/Specs.hpp" @@ -42,6 +43,7 @@ namespace rpc { */ class AMMInfoHandler { std::shared_ptr sharedPtrBackend_; + std::shared_ptr amendmentCenter_; public: /** @@ -82,8 +84,13 @@ public: * @brief Construct a new AMMInfoHandler object * * @param sharedPtrBackend The backend to use + * @param amendmentCenter The amendmentCenter to use */ - AMMInfoHandler(std::shared_ptr const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend) + AMMInfoHandler( + std::shared_ptr const& sharedPtrBackend, + std::shared_ptr const& amendmentCenter + ) + : sharedPtrBackend_(sharedPtrBackend), amendmentCenter_{amendmentCenter} { } diff --git a/src/rpc/handlers/BookOffers.cpp b/src/rpc/handlers/BookOffers.cpp index 65110ecb..f63c98be 100644 --- a/src/rpc/handlers/BookOffers.cpp +++ b/src/rpc/handlers/BookOffers.cpp @@ -72,7 +72,13 @@ BookOffersHandler::process(Input input, Context const& ctx) const output.ledgerHash = ripple::strHex(lgrInfo.hash); output.ledgerIndex = lgrInfo.seq; output.offers = postProcessOrderBook( - offers, book, input.taker ? *(input.taker) : beast::zero, *sharedPtrBackend_, lgrInfo.seq, ctx.yield + offers, + book, + input.taker ? *(input.taker) : beast::zero, + *sharedPtrBackend_, + *amendmentCenter_, + lgrInfo.seq, + ctx.yield ); return output; diff --git a/src/rpc/handlers/BookOffers.hpp b/src/rpc/handlers/BookOffers.hpp index 01d2b253..cd7eed6d 100644 --- a/src/rpc/handlers/BookOffers.hpp +++ b/src/rpc/handlers/BookOffers.hpp @@ -19,6 +19,7 @@ #pragma once +#include "data/AmendmentCenterInterface.hpp" #include "data/BackendInterface.hpp" #include "rpc/Errors.hpp" #include "rpc/JS.hpp" @@ -51,6 +52,7 @@ namespace rpc { */ class BookOffersHandler { std::shared_ptr sharedPtrBackend_; + std::shared_ptr amendmentCenter_; public: static constexpr auto kLIMIT_MIN = 1; @@ -91,8 +93,13 @@ public: * @brief Construct a new BookOffersHandler object * * @param sharedPtrBackend The backend to use + * @param amendmentCenter The amendmentCenter to use */ - BookOffersHandler(std::shared_ptr const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend) + BookOffersHandler( + std::shared_ptr const& sharedPtrBackend, + std::shared_ptr const& amendmentCenter + ) + : sharedPtrBackend_(sharedPtrBackend), amendmentCenter_{amendmentCenter} { } diff --git a/src/rpc/handlers/Ledger.cpp b/src/rpc/handlers/Ledger.cpp index f6b7dd59..519b983a 100644 --- a/src/rpc/handlers/Ledger.cpp +++ b/src/rpc/handlers/Ledger.cpp @@ -134,6 +134,7 @@ LedgerHandler::process(LedgerHandler::Input input, Context const& ctx) const if (account != amount.getIssuer()) { auto const ownerFunds = accountHolds( *sharedPtrBackend_, + *amendmentCenter_, lgrInfo.seq, account, amount.getCurrency(), diff --git a/src/rpc/handlers/Ledger.hpp b/src/rpc/handlers/Ledger.hpp index b507dd70..eb8f5fb4 100644 --- a/src/rpc/handlers/Ledger.hpp +++ b/src/rpc/handlers/Ledger.hpp @@ -19,6 +19,7 @@ #pragma once +#include "data/AmendmentCenterInterface.hpp" #include "data/BackendInterface.hpp" #include "rpc/JS.hpp" #include "rpc/common/Checkers.hpp" @@ -45,6 +46,7 @@ namespace rpc { */ class LedgerHandler { std::shared_ptr sharedPtrBackend_; + std::shared_ptr amendmentCenter_; public: /** @@ -89,8 +91,13 @@ public: * @brief Construct a new LedgerHandler object * * @param sharedPtrBackend The backend to use + * @param amendmentCenter The amendmentCenter to use */ - LedgerHandler(std::shared_ptr const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend) + LedgerHandler( + std::shared_ptr const& sharedPtrBackend, + std::shared_ptr amendmentCenter + ) + : sharedPtrBackend_(sharedPtrBackend), amendmentCenter_(amendmentCenter) { } diff --git a/src/rpc/handlers/Subscribe.cpp b/src/rpc/handlers/Subscribe.cpp index 206e2336..5fbe62f0 100644 --- a/src/rpc/handlers/Subscribe.cpp +++ b/src/rpc/handlers/Subscribe.cpp @@ -55,9 +55,10 @@ namespace rpc { SubscribeHandler::SubscribeHandler( std::shared_ptr const& sharedPtrBackend, + std::shared_ptr const& amendmentCenter, std::shared_ptr const& subscriptions ) - : sharedPtrBackend_(sharedPtrBackend), subscriptions_(subscriptions) + : sharedPtrBackend_(sharedPtrBackend), amendmentCenter_(amendmentCenter), subscriptions_(subscriptions) { } @@ -216,8 +217,9 @@ SubscribeHandler::subscribeToBooks( // https://github.com/XRPLF/xrpl-dev-portal/issues/1818 auto const takerID = internalBook.taker ? accountFromStringStrict(*(internalBook.taker)) : beast::zero; - auto const orderBook = - postProcessOrderBook(offers, book, *takerID, *sharedPtrBackend_, rng->maxSequence, yield); + auto const orderBook = postProcessOrderBook( + offers, book, *takerID, *sharedPtrBackend_, *amendmentCenter_, rng->maxSequence, yield + ); std::copy(orderBook.begin(), orderBook.end(), std::back_inserter(snapshots)); }; diff --git a/src/rpc/handlers/Subscribe.hpp b/src/rpc/handlers/Subscribe.hpp index 89c295c1..3e3e16af 100644 --- a/src/rpc/handlers/Subscribe.hpp +++ b/src/rpc/handlers/Subscribe.hpp @@ -19,6 +19,7 @@ #pragma once +#include "data/AmendmentCenterInterface.hpp" #include "data/BackendInterface.hpp" #include "feed/SubscriptionManagerInterface.hpp" #include "feed/Types.hpp" @@ -53,6 +54,7 @@ namespace rpc { class SubscribeHandler { std::shared_ptr sharedPtrBackend_; + std::shared_ptr amendmentCenter_; std::shared_ptr subscriptions_; public: @@ -98,10 +100,12 @@ public: * @brief Construct a new BaseSubscribeHandler object * * @param sharedPtrBackend The backend to use + * @param amendmentCenter The amendmentCenter to use * @param subscriptions The subscription manager to use */ SubscribeHandler( std::shared_ptr const& sharedPtrBackend, + std::shared_ptr const& amendmentCenter, std::shared_ptr const& subscriptions ); diff --git a/tests/common/feed/FeedTestUtil.hpp b/tests/common/feed/FeedTestUtil.hpp index 320c2d59..adb3974e 100644 --- a/tests/common/feed/FeedTestUtil.hpp +++ b/tests/common/feed/FeedTestUtil.hpp @@ -19,6 +19,7 @@ #pragma once +#include "util/MockAmendmentCenter.hpp" #include "util/MockBackendTestFixture.hpp" #include "util/MockPrometheus.hpp" #include "util/MockWsBase.hpp" @@ -43,9 +44,10 @@ protected: web::SubscriptionContextPtr sessionPtr = std::make_shared(); std::shared_ptr testFeedPtr = std::make_shared(ctx_); MockSession* mockSessionPtr = dynamic_cast(sessionPtr.get()); + StrictMockAmendmentCenterSharedPtr mockAmendmentCenterPtr_; }; -namespace impl { +namespace feed::impl { class SharedStringJsonEqMatcher { std::string expected_; @@ -74,12 +76,12 @@ public: *os << "Expecting json " << expected_; } }; -} // namespace impl +} // namespace feed::impl // NOLINTEND(readability-identifier-naming) inline ::testing::Matcher> sharedStringJsonEq(std::string const& expected) { - return impl::SharedStringJsonEqMatcher(expected); + return feed::impl::SharedStringJsonEqMatcher(expected); } diff --git a/tests/common/util/TestObject.cpp b/tests/common/util/TestObject.cpp index 55e9f844..f04149e6 100644 --- a/tests/common/util/TestObject.cpp +++ b/tests/common/util/TestObject.cpp @@ -247,7 +247,8 @@ createAccountRootObject( uint32_t ownerCount, std::string_view previousTxnID, uint32_t previousTxnSeq, - uint32_t transferRate + uint32_t transferRate, + std::optional ammID ) { ripple::STObject accountRoot(ripple::sfAccount); @@ -260,6 +261,10 @@ createAccountRootObject( accountRoot.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{previousTxnID}); accountRoot.setFieldU32(ripple::sfPreviousTxnLgrSeq, previousTxnSeq); accountRoot.setFieldU32(ripple::sfTransferRate, transferRate); + + if (ammID) + accountRoot.setFieldH256(ripple::sfAMMID, *ammID); + return accountRoot; } diff --git a/tests/common/util/TestObject.hpp b/tests/common/util/TestObject.hpp index 1bed19bf..20b6682b 100644 --- a/tests/common/util/TestObject.hpp +++ b/tests/common/util/TestObject.hpp @@ -146,7 +146,8 @@ createAccountRootObject( uint32_t ownerCount, std::string_view previousTxnID, uint32_t previousTxnSeq, - uint32_t transferRate = 0 + uint32_t transferRate = 0, + std::optional ammID = std::nullopt ); /* diff --git a/tests/unit/feed/SubscriptionManagerTests.cpp b/tests/unit/feed/SubscriptionManagerTests.cpp index 743c4fc0..f8322426 100644 --- a/tests/unit/feed/SubscriptionManagerTests.cpp +++ b/tests/unit/feed/SubscriptionManagerTests.cpp @@ -21,6 +21,7 @@ #include "feed/FeedTestUtil.hpp" #include "feed/SubscriptionManager.hpp" #include "util/Assert.hpp" +#include "util/MockAmendmentCenter.hpp" #include "util/MockBackendTestFixture.hpp" #include "util/MockPrometheus.hpp" #include "util/MockWsBase.hpp" @@ -66,8 +67,9 @@ protected: ASSERT(sessionPtr_ != nullptr, "dynamic_cast failed"); } + StrictMockAmendmentCenterSharedPtr mockAmendmentCenterPtr_; std::shared_ptr subscriptionManagerPtr_ = - std::make_shared(Execution(2), backend_); + std::make_shared(Execution(2), backend_, mockAmendmentCenterPtr_); web::SubscriptionContextPtr session_ = std::make_shared(); MockSession* sessionPtr_ = dynamic_cast(session_.get()); }; diff --git a/tests/unit/feed/TransactionFeedTests.cpp b/tests/unit/feed/TransactionFeedTests.cpp index 8dc38043..bb2034b1 100644 --- a/tests/unit/feed/TransactionFeedTests.cpp +++ b/tests/unit/feed/TransactionFeedTests.cpp @@ -17,6 +17,7 @@ */ //============================================================================== +#include "data/AmendmentCenter.hpp" #include "data/Types.hpp" #include "feed/FeedTestUtil.hpp" #include "feed/impl/TransactionFeed.hpp" @@ -51,6 +52,8 @@ constexpr auto kLEDGER_HASH = "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014 constexpr auto kCURRENCY = "0158415500000000C1F76FF6ECB0BAC600000000"; constexpr auto kISSUER = "rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD"; constexpr auto kTXN_ID = "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC321"; +constexpr auto kAMM_ACCOUNT = "rnW8FAPgpQgA6VoESnVrUVJHBdq9QAtRZs"; +constexpr auto kLPTOKEN_CURRENCY = "037C35306B24AAB7FF90848206E003279AA47090"; constexpr auto kTRAN_V1 = R"({ @@ -183,10 +186,10 @@ TEST_F(FeedTransactionTest, SubTransactionV1) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(1)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V1))); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsub(sessionPtr); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); EXPECT_EQ(testFeedPtr->transactionSubCount(), 0); } @@ -205,10 +208,10 @@ TEST_F(FeedTransactionTest, SubTransactionForProposedTx) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(1)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V1))); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsubProposed(sessionPtr); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, SubTransactionV2) @@ -226,12 +229,12 @@ TEST_F(FeedTransactionTest, SubTransactionV2) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(2)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V2))); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsub(sessionPtr); EXPECT_EQ(testFeedPtr->transactionSubCount(), 0); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, SubAccountV1) @@ -252,12 +255,12 @@ TEST_F(FeedTransactionTest, SubAccountV1) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(1)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V1))); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsub(account, sessionPtr); EXPECT_EQ(testFeedPtr->accountSubCount(), 0); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, SubForProposedAccount) @@ -278,10 +281,10 @@ TEST_F(FeedTransactionTest, SubForProposedAccount) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(1)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V1))); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsubProposed(account, sessionPtr); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, SubAccountV2) @@ -301,12 +304,12 @@ TEST_F(FeedTransactionTest, SubAccountV2) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(2)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V2))); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsub(account, sessionPtr); EXPECT_EQ(testFeedPtr->accountSubCount(), 0); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, SubBothTransactionAndAccount) @@ -328,14 +331,14 @@ TEST_F(FeedTransactionTest, SubBothTransactionAndAccount) EXPECT_CALL(*mockSessionPtr, apiSubversion).Times(2).WillRepeatedly(testing::Return(2)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V2))).Times(2); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsub(account, sessionPtr); EXPECT_EQ(testFeedPtr->accountSubCount(), 0); testFeedPtr->unsub(sessionPtr); EXPECT_EQ(testFeedPtr->transactionSubCount(), 0); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, SubBookV1) @@ -418,7 +421,7 @@ TEST_F(FeedTransactionTest, SubBookV1) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(1)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kORDERBOOK_PUBLISH))).Times(1); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); // trigger by offer cancel meta data metaObj = createMetaDataForCancelOffer(kCURRENCY, kISSUER, 22, 3, 1); @@ -474,7 +477,7 @@ TEST_F(FeedTransactionTest, SubBookV1) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(1)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kORDERBOOK_CANCEL_PUBLISH))).Times(1); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); // trigger by offer create meta data static constexpr auto kORDERBOOK_CREATE_PUBLISH = @@ -531,12 +534,12 @@ TEST_F(FeedTransactionTest, SubBookV1) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(1)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kORDERBOOK_CREATE_PUBLISH))).Times(1); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsub(book, sessionPtr); EXPECT_EQ(testFeedPtr->bookSubCount(), 0); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, SubBookV2) @@ -619,12 +622,12 @@ TEST_F(FeedTransactionTest, SubBookV2) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(2)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kORDERBOOK_PUBLISH))).Times(1); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsub(book, sessionPtr); EXPECT_EQ(testFeedPtr->bookSubCount(), 0); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, TransactionContainsBothAccountsSubed) @@ -649,18 +652,18 @@ TEST_F(FeedTransactionTest, TransactionContainsBothAccountsSubed) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(2)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V2))).Times(1); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsub(account, sessionPtr); EXPECT_EQ(testFeedPtr->accountSubCount(), 1); EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(2)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V2))).Times(1); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsub(account2, sessionPtr); EXPECT_EQ(testFeedPtr->accountSubCount(), 0); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, SubAccountRepeatWithDifferentVersion) @@ -686,19 +689,19 @@ TEST_F(FeedTransactionTest, SubAccountRepeatWithDifferentVersion) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(2)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V2))).Times(1); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsub(account, sessionPtr); EXPECT_EQ(testFeedPtr->accountSubCount(), 1); EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(2)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V2))).Times(1); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsub(account2, sessionPtr); EXPECT_EQ(testFeedPtr->accountSubCount(), 0); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, SubTransactionRepeatWithDifferentVersion) @@ -720,12 +723,12 @@ TEST_F(FeedTransactionTest, SubTransactionRepeatWithDifferentVersion) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(2)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V2))).Times(1); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsub(sessionPtr); EXPECT_EQ(testFeedPtr->transactionSubCount(), 0); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, SubRepeat) @@ -865,7 +868,10 @@ TEST_F(FeedTransactionTest, PubTransactionWithOwnerFund) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(1)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRANSACTION_FOR_OWNER_FUND))).Times(1); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + EXPECT_CALL(*mockAmendmentCenterPtr_, isEnabled(testing::_, Amendments::fixFrozenLPTokenTransfer, testing::_)); + ON_CALL(*mockAmendmentCenterPtr_, isEnabled(testing::_, Amendments::fixFrozenLPTokenTransfer, testing::_)) + .WillByDefault(testing::Return(false)); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } static constexpr auto kTRAN_FROZEN = @@ -941,7 +947,7 @@ TEST_F(FeedTransactionTest, PubTransactionOfferCreationFrozenLine) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(1)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_FROZEN))).Times(1); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, SubTransactionOfferCreationGlobalFrozen) @@ -982,7 +988,7 @@ TEST_F(FeedTransactionTest, SubTransactionOfferCreationGlobalFrozen) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(1)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_FROZEN))).Times(1); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, SubBothProposedAndValidatedAccount) @@ -1005,13 +1011,13 @@ TEST_F(FeedTransactionTest, SubBothProposedAndValidatedAccount) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(1)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V1))).Times(1); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsub(account, sessionPtr); testFeedPtr->unsubProposed(account, sessionPtr); EXPECT_EQ(testFeedPtr->accountSubCount(), 0); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, SubBothProposedAndValidated) @@ -1032,11 +1038,11 @@ TEST_F(FeedTransactionTest, SubBothProposedAndValidated) EXPECT_CALL(*mockSessionPtr, apiSubversion).Times(2).WillRepeatedly(testing::Return(1)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V1))).Times(2); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); testFeedPtr->unsub(sessionPtr); testFeedPtr->unsubProposed(sessionPtr); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, SubProposedDisconnect) @@ -1054,10 +1060,10 @@ TEST_F(FeedTransactionTest, SubProposedDisconnect) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(1)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V1))).Times(1); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); sessionPtr.reset(); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } TEST_F(FeedTransactionTest, SubProposedAccountDisconnect) @@ -1077,10 +1083,111 @@ TEST_F(FeedTransactionTest, SubProposedAccountDisconnect) EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(1)); EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRAN_V1))).Times(1); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); sessionPtr.reset(); - testFeedPtr->pub(trans1, ledgerHeader, backend_); + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); +} + +// This test exercises `accountHold` for amendment fixFrozenLPTokenTransfer, so that the output shows "owner_funds: 0" +// if the currency in the amm pool is frozen +TEST_F(FeedTransactionTest, PubTransactionWithOwnerFundFrozenLPToken) +{ + EXPECT_CALL(*mockSessionPtr, onDisconnect); + testFeedPtr->sub(sessionPtr); + + auto const ledgerHeader = createLedgerHeader(kLEDGER_HASH, 33); + auto trans1 = TransactionAndMetadata(); + ripple::STObject const obj = + createCreateOfferTransactionObject(kACCOUNT1, 1, 32, kLPTOKEN_CURRENCY, kAMM_ACCOUNT, 1, 3); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + ripple::STArray const metaArray{0}; + ripple::STObject metaObj(ripple::sfTransactionMetaData); + metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); + metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); + metaObj.setFieldU32(ripple::sfTransactionIndex, 22); + trans1.metadata = metaObj.getSerializer().peekData(); + + ripple::STObject line(ripple::sfIndexes); + line.setFieldU16(ripple::sfLedgerEntryType, ripple::ltRIPPLE_STATE); + line.setFieldAmount(ripple::sfLowLimit, ripple::STAmount(10, false)); + line.setFieldAmount(ripple::sfHighLimit, ripple::STAmount(100, false)); + line.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{kTXN_ID}); + line.setFieldU32(ripple::sfPreviousTxnLgrSeq, 3); + line.setFieldU32(ripple::sfFlags, 0); + auto const issue2 = getIssue(kLPTOKEN_CURRENCY, kAMM_ACCOUNT); + line.setFieldAmount(ripple::sfBalance, ripple::STAmount(issue2, 100)); + + EXPECT_CALL(*backend_, doFetchLedgerObject(testing::_, testing::_, testing::_)) + .Times(2) + .WillRepeatedly(testing::Return(line.getSerializer().peekData())); + + auto const ammID = ripple::uint256{54321}; + + // create an amm account because in `accountHolds` checks for the ammID + auto const ammAccount = getAccountIdWithString(kAMM_ACCOUNT); + auto const kk = ripple::keylet::account(ammAccount).key; + ripple::STObject const ammAccountRoot = createAccountRootObject(kAMM_ACCOUNT, 0, 1, 10, 2, kTXN_ID, 3, 0, ammID); + EXPECT_CALL(*backend_, doFetchLedgerObject(kk, testing::_, testing::_)) + .Times(2) + .WillRepeatedly(testing::Return(ammAccountRoot.getSerializer().peekData())); + + static constexpr auto kTRANSACTION_FOR_OWNER_FUND = + R"({ + "transaction": + { + "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Fee":"1", + "Sequence":32, + "SigningPubKey":"74657374", + "TakerGets": + { + "currency":"037C35306B24AAB7FF90848206E003279AA47090", + "issuer":"rnW8FAPgpQgA6VoESnVrUVJHBdq9QAtRZs", + "value":"1" + }, + "TakerPays":"3", + "TransactionType":"OfferCreate", + "hash":"9CA8BBF209DC4505F593A1EA0DC2135A5FA2C6541AF19D128B046873E0CEB695", + "date":0, + "owner_funds":"0" + }, + "meta": + { + "AffectedNodes":[], + "TransactionIndex":22, + "TransactionResult":"tesSUCCESS" + }, + "type":"transaction", + "validated":true, + "status":"closed", + "ledger_index":33, + "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "engine_result_code":0, + "close_time_iso": "2000-01-01T00:00:00Z", + "engine_result":"tesSUCCESS", + "engine_result_message":"The transaction was applied. Only final in a validated ledger." + })"; + + EXPECT_CALL(*mockSessionPtr, apiSubversion).WillOnce(testing::Return(1)); + EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kTRANSACTION_FOR_OWNER_FUND))).Times(1); + + EXPECT_CALL(*mockAmendmentCenterPtr_, isEnabled(testing::_, Amendments::fixFrozenLPTokenTransfer, testing::_)) + .WillOnce(testing::Return(true)); + + auto const ammObj = + createAmmObject(kAMM_ACCOUNT, "XRP", ripple::toBase58(ripple::xrpAccount()), kCURRENCY, kISSUER); + EXPECT_CALL(*backend_, doFetchLedgerObject(ripple::keylet::amm(ammID).key, testing::_, testing::_)) + .WillOnce(testing::Return(ammObj.getSerializer().peekData())); + + // create the issuer account that enacted global freeze + auto const issuerAccount = getAccountIdWithString(kISSUER); + ripple::STObject const issuerAccountRoot = createAccountRootObject(kISSUER, 4194304, 1, 10, 2, kTXN_ID, 3); + EXPECT_CALL(*backend_, doFetchLedgerObject(ripple::keylet::account(issuerAccount).key, testing::_, testing::_)) + .WillOnce(testing::Return(issuerAccountRoot.getSerializer().peekData())); + + testFeedPtr->pub(trans1, ledgerHeader, backend_, mockAmendmentCenterPtr_); } struct TransactionFeedMockPrometheusTest : WithMockPrometheus, SyncExecutionCtxFixture { diff --git a/tests/unit/rpc/RPCHelpersTests.cpp b/tests/unit/rpc/RPCHelpersTests.cpp index 7c3e7dfd..f0a2ad46 100644 --- a/tests/unit/rpc/RPCHelpersTests.cpp +++ b/tests/unit/rpc/RPCHelpersTests.cpp @@ -17,12 +17,14 @@ */ //============================================================================== +#include "data/AmendmentCenter.hpp" #include "data/Types.hpp" #include "rpc/Errors.hpp" #include "rpc/JS.hpp" #include "rpc/RPCHelpers.hpp" #include "rpc/common/Types.hpp" #include "util/AsioContextTestFixture.hpp" +#include "util/MockAmendmentCenter.hpp" #include "util/MockBackendTestFixture.hpp" #include "util/MockPrometheus.hpp" #include "util/NameGenerator.hpp" @@ -38,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +66,10 @@ constexpr auto kACCOUNT2 = "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun"; constexpr auto kINDEX1 = "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC321"; constexpr auto kINDEX2 = "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC322"; constexpr auto kTXN_ID = "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC321"; +constexpr auto kAMM_ACCOUNT = "rnW8FAPgpQgA6VoESnVrUVJHBdq9QAtRZs"; +constexpr auto kISSUER = "rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD"; +constexpr auto kLPTOKEN_CURRENCY = "037C35306B24AAB7FF90848206E003279AA47090"; +constexpr auto kAMM_ID = 54321; } // namespace @@ -77,6 +84,9 @@ class RPCHelpersTest : public util::prometheus::WithPrometheus, public MockBacke { SyncAsioContextTest::TearDown(); } + +protected: + StrictMockAmendmentCenterSharedPtr mockAmendmentCenterPtr_; }; TEST_F(RPCHelpersTest, TraverseOwnedNodesMarkerInvalidIndexNotHex) @@ -547,6 +557,247 @@ TEST_F(RPCHelpersTest, ParseIssue) ); } +TEST_F(RPCHelpersTest, AccountHoldsFixLPTAmendmentDisabled) +{ + auto ammAccount = getAccountIdWithString(kAMM_ACCOUNT); + auto account = getAccountIdWithString(kACCOUNT); + + auto const lptRippleState = createRippleStateLedgerObject( + kLPTOKEN_CURRENCY, kAMM_ACCOUNT, 100, kACCOUNT, 100, kAMM_ACCOUNT, 100, kTXN_ID, 3 + ); + auto const lptRippleStateKk = ripple::keylet::line(ammAccount, account, ripple::to_currency(kLPTOKEN_CURRENCY)).key; + + // trustline fetched twice. once in accountHolds and once in isFrozen + EXPECT_CALL(*backend_, doFetchLedgerObject(lptRippleStateKk, testing::_, testing::_)) + .Times(2) + .WillRepeatedly(Return(lptRippleState.getSerializer().peekData())); + + auto const ammID = ripple::uint256{kAMM_ID}; + auto const ammAccountKk = ripple::keylet::account(ammAccount).key; + auto const ammAccountRoot = createAccountRootObject(kAMM_ACCOUNT, 0, 2, 200, 2, kINDEX1, 2, 0, ammID); + + EXPECT_CALL(*backend_, doFetchLedgerObject(ammAccountKk, testing::_, testing::_)) + .WillOnce(Return(ammAccountRoot.getSerializer().peekData())); + + EXPECT_CALL(*mockAmendmentCenterPtr_, isEnabled(testing::_, Amendments::fixFrozenLPTokenTransfer, testing::_)) + .WillOnce(Return(false)); + + boost::asio::spawn(ctx_, [&, this](boost::asio::yield_context yield) { + auto ret = accountHolds( + *backend_, + *mockAmendmentCenterPtr_, + 0, + account, + ripple::to_currency(kLPTOKEN_CURRENCY), + ammAccount, + true, + yield + ); + EXPECT_EQ(ret.mantissa(), 1000000000000000); + }); + ctx_.run(); +} + +TEST_F(RPCHelpersTest, AccountHoldsLPTokenNotAMMAccount) +{ + auto account = getAccountIdWithString(kACCOUNT); + auto account2 = getAccountIdWithString(kACCOUNT2); + + auto const usdRippleState = + createRippleStateLedgerObject("USD", kACCOUNT2, 100, kACCOUNT, 100, kACCOUNT2, 100, kTXN_ID, 3); + auto const usdRippleStateKk = ripple::keylet::line(account2, account, ripple::to_currency("USD")).key; + + // trustline fetched twice. once in accountHolds and once in isFrozen + EXPECT_CALL(*backend_, doFetchLedgerObject(usdRippleStateKk, testing::_, testing::_)) + .Times(2) + .WillRepeatedly(Return(usdRippleState.getSerializer().peekData())); + + EXPECT_CALL(*mockAmendmentCenterPtr_, isEnabled(testing::_, Amendments::fixFrozenLPTokenTransfer, testing::_)) + .WillOnce(Return(true)); + + auto const account2Kk = ripple::keylet::account(account2).key; + auto const account2Root = createAccountRootObject(kACCOUNT2, 0, 2, 200, 2, kINDEX1, 2, 0); + + EXPECT_CALL(*backend_, doFetchLedgerObject(account2Kk, testing::_, testing::_)) + .Times(2) + .WillRepeatedly(Return(account2Root.getSerializer().peekData())); + + boost::asio::spawn(ctx_, [&, this](boost::asio::yield_context yield) { + auto ret = accountHolds( + *backend_, *mockAmendmentCenterPtr_, 0, account, ripple::to_currency("USD"), account2, true, yield + ); + EXPECT_EQ(ret.mantissa(), 1000000000000000); + }); + ctx_.run(); +} + +TEST_F(RPCHelpersTest, AccountHoldsLPTokenAsset1Frozen) +{ + auto ammAccount = getAccountIdWithString(kAMM_ACCOUNT); + auto account = getAccountIdWithString(kACCOUNT); + auto issuer = getAccountIdWithString(kISSUER); + + auto const lptRippleState = createRippleStateLedgerObject( + kLPTOKEN_CURRENCY, kAMM_ACCOUNT, 100, kACCOUNT, 100, kAMM_ACCOUNT, 100, kTXN_ID, 3 + ); + auto const lptRippleStateKk = ripple::keylet::line(ammAccount, account, ripple::to_currency(kLPTOKEN_CURRENCY)).key; + + // trustline fetched twice. once in accountHolds and once in isFrozen + EXPECT_CALL(*backend_, doFetchLedgerObject(lptRippleStateKk, testing::_, testing::_)) + .Times(2) + .WillRepeatedly(Return(lptRippleState.getSerializer().peekData())); + + EXPECT_CALL(*mockAmendmentCenterPtr_, isEnabled(testing::_, Amendments::fixFrozenLPTokenTransfer, testing::_)) + .WillOnce(Return(true)); + + auto const ammID = ripple::uint256{kAMM_ID}; + auto const ammAccountKk = ripple::keylet::account(ammAccount).key; + auto const ammAccountRoot = createAccountRootObject(kAMM_ACCOUNT, 0, 2, 200, 2, kINDEX1, 2, 0, ammID); + + // accountroot fetched twice, once in isFrozen, once in accountHolds + EXPECT_CALL(*backend_, doFetchLedgerObject(ammAccountKk, testing::_, testing::_)) + .Times(2) + .WillRepeatedly(Return(ammAccountRoot.getSerializer().peekData())); + + auto const amm = createAmmObject(kAMM_ACCOUNT, "USD", kISSUER, "XRP", ripple::toBase58(ripple::xrpAccount())); + EXPECT_CALL(*backend_, doFetchLedgerObject(ripple::keylet::amm(ammID).key, testing::_, testing::_)) + .Times(1) + .WillOnce(Return(amm.getSerializer().peekData())); + + auto const issuerKk = ripple::keylet::account(issuer).key; + auto const issuerAccountRoot = createAccountRootObject(kISSUER, ripple::lsfGlobalFreeze, 2, 200, 2, kINDEX1, 2, 0); + EXPECT_CALL(*backend_, doFetchLedgerObject(issuerKk, testing::_, testing::_)) + .WillOnce(Return(issuerAccountRoot.getSerializer().peekData())); + + boost::asio::spawn(ctx_, [&, this](boost::asio::yield_context yield) { + auto ret = accountHolds( + *backend_, + *mockAmendmentCenterPtr_, + 0, + account, + ripple::to_currency(kLPTOKEN_CURRENCY), + ammAccount, + true, + yield + ); + EXPECT_EQ(ret.mantissa(), 0); + }); + ctx_.run(); +} + +TEST_F(RPCHelpersTest, AccountHoldsLPTokenAsset2Frozen) +{ + auto ammAccount = getAccountIdWithString(kAMM_ACCOUNT); + auto account = getAccountIdWithString(kACCOUNT); + auto issuer = getAccountIdWithString(kISSUER); + + auto const lptRippleState = createRippleStateLedgerObject( + kLPTOKEN_CURRENCY, kAMM_ACCOUNT, 100, kACCOUNT, 100, kAMM_ACCOUNT, 100, kTXN_ID, 3 + ); + auto const lptRippleStateKk = ripple::keylet::line(ammAccount, account, ripple::to_currency(kLPTOKEN_CURRENCY)).key; + + // trustline fetched twice. once in accountHolds and once in isFrozen + EXPECT_CALL(*backend_, doFetchLedgerObject(lptRippleStateKk, testing::_, testing::_)).Times(2); + ON_CALL(*backend_, doFetchLedgerObject(lptRippleStateKk, testing::_, testing::_)) + .WillByDefault(testing::Return(lptRippleState.getSerializer().peekData())); + + EXPECT_CALL(*mockAmendmentCenterPtr_, isEnabled(testing::_, Amendments::fixFrozenLPTokenTransfer, testing::_)) + .WillOnce(testing::Return(true)); + + auto const ammID = ripple::uint256{kAMM_ID}; + auto const ammAccountKk = ripple::keylet::account(ammAccount).key; + auto const ammAccountRoot = createAccountRootObject(kAMM_ACCOUNT, 0, 2, 200, 2, kINDEX1, 2, 0, ammID); + + // accountroot fetched twice, once in isFrozen, once in accountHolds + EXPECT_CALL(*backend_, doFetchLedgerObject(ammAccountKk, testing::_, testing::_)) + .Times(2) + .WillRepeatedly(Return(ammAccountRoot.getSerializer().peekData())); + + auto const amm = createAmmObject(kAMM_ACCOUNT, "XRP", ripple::toBase58(ripple::xrpAccount()), "USD", kISSUER); + EXPECT_CALL(*backend_, doFetchLedgerObject(ripple::keylet::amm(ammID).key, testing::_, testing::_)) + .WillOnce(Return(amm.getSerializer().peekData())); + + auto const issuerKk = ripple::keylet::account(issuer).key; + auto const issuerAccountRoot = createAccountRootObject(kISSUER, ripple::lsfGlobalFreeze, 2, 200, 2, kINDEX1, 2, 0); + EXPECT_CALL(*backend_, doFetchLedgerObject(issuerKk, testing::_, testing::_)) + .WillOnce(Return(issuerAccountRoot.getSerializer().peekData())); + + boost::asio::spawn(ctx_, [&, this](boost::asio::yield_context yield) { + auto ret = accountHolds( + *backend_, + *mockAmendmentCenterPtr_, + 0, + account, + ripple::to_currency(kLPTOKEN_CURRENCY), + ammAccount, + true, + yield + ); + EXPECT_EQ(ret.mantissa(), 0); + }); + ctx_.run(); +} + +TEST_F(RPCHelpersTest, AccountHoldsLPTokenUnfrozen) +{ + auto ammAccount = getAccountIdWithString(kAMM_ACCOUNT); + auto account = getAccountIdWithString(kACCOUNT); + auto issuer = getAccountIdWithString(kISSUER); + + auto const lptRippleState = createRippleStateLedgerObject( + kLPTOKEN_CURRENCY, kAMM_ACCOUNT, 100, kACCOUNT, 100, kAMM_ACCOUNT, 100, kTXN_ID, 3 + ); + auto const lptRippleStateKk = ripple::keylet::line(ammAccount, account, ripple::to_currency(kLPTOKEN_CURRENCY)).key; + + // trustline fetched twice. once in accountHolds and once in isFrozen + EXPECT_CALL(*backend_, doFetchLedgerObject(lptRippleStateKk, testing::_, testing::_)) + .Times(2) + .WillRepeatedly(Return(lptRippleState.getSerializer().peekData())); + + EXPECT_CALL(*mockAmendmentCenterPtr_, isEnabled(testing::_, Amendments::fixFrozenLPTokenTransfer, testing::_)) + .WillOnce(Return(true)); + + auto const ammID = ripple::uint256{kAMM_ID}; + auto const ammAccountKk = ripple::keylet::account(ammAccount).key; + auto const ammAccountRoot = createAccountRootObject(kAMM_ACCOUNT, 0, 2, 200, 2, kINDEX1, 2, 0, ammID); + + // accountroot fetched twice, once in isFrozen, once in accountHolds + EXPECT_CALL(*backend_, doFetchLedgerObject(ammAccountKk, testing::_, testing::_)) + .Times(2) + .WillRepeatedly(Return(ammAccountRoot.getSerializer().peekData())); + + auto const amm = createAmmObject(kAMM_ACCOUNT, "XRP", ripple::toBase58(ripple::xrpAccount()), "USD", kISSUER); + EXPECT_CALL(*backend_, doFetchLedgerObject(ripple::keylet::amm(ammID).key, testing::_, testing::_)) + .WillOnce(Return(amm.getSerializer().peekData())); + + auto const issuerKk = ripple::keylet::account(issuer).key; + auto const issuerAccountRoot = createAccountRootObject(kISSUER, 0, 2, 200, 2, kINDEX1, 2, 0); + EXPECT_CALL(*backend_, doFetchLedgerObject(issuerKk, testing::_, testing::_)) + .WillOnce(Return(issuerAccountRoot.getSerializer().peekData())); + + auto const usdRippleState = + createRippleStateLedgerObject("USD", kISSUER, 100, kACCOUNT, 100, kISSUER, 100, kTXN_ID, 3); + auto const usdRippleStateKk = ripple::keylet::line(issuer, account, ripple::to_currency("USD")).key; + + EXPECT_CALL(*backend_, doFetchLedgerObject(usdRippleStateKk, testing::_, testing::_)) + .WillOnce(Return(usdRippleState.getSerializer().peekData())); + + boost::asio::spawn(ctx_, [&, this](boost::asio::yield_context yield) { + auto ret = accountHolds( + *backend_, + *mockAmendmentCenterPtr_, + 0, + account, + ripple::to_currency(kLPTOKEN_CURRENCY), + ammAccount, + true, + yield + ); + EXPECT_EQ(ret.mantissa(), 1000000000000000); + }); + ctx_.run(); +} + struct IsAdminCmdParamTestCaseBundle { std::string testName; std::string method; diff --git a/tests/unit/rpc/handlers/AMMInfoTests.cpp b/tests/unit/rpc/handlers/AMMInfoTests.cpp index ee428e1b..f483e79e 100644 --- a/tests/unit/rpc/handlers/AMMInfoTests.cpp +++ b/tests/unit/rpc/handlers/AMMInfoTests.cpp @@ -23,6 +23,7 @@ #include "rpc/common/Types.hpp" #include "rpc/handlers/AMMInfo.hpp" #include "util/HandlerBaseTestFixture.hpp" +#include "util/MockAmendmentCenter.hpp" #include "util/NameGenerator.hpp" #include "util/TestObject.hpp" @@ -67,6 +68,9 @@ struct RPCAMMInfoHandlerTest : HandlerBaseTest { { backend_->setRange(10, 30); } + +protected: + StrictMockAmendmentCenterSharedPtr mockAmendmentCenterPtr_; }; struct AMMInfoParamTestCaseBundle { @@ -150,7 +154,7 @@ TEST_P(AMMInfoParameterTest, InvalidParams) { auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -183,7 +187,7 @@ TEST_F(RPCAMMInfoHandlerTest, AccountNotFound) kNOTFOUND_ACCOUNT )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); ASSERT_FALSE(output); @@ -207,7 +211,7 @@ TEST_F(RPCAMMInfoHandlerTest, AMMAccountNotExist) kWRONG_AMM_ACCOUNT )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); ASSERT_FALSE(output); @@ -230,7 +234,7 @@ TEST_F(RPCAMMInfoHandlerTest, AMMAccountNotInDBIsMalformed) kAMM_ACCOUNT )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); ASSERT_FALSE(output); @@ -256,7 +260,7 @@ TEST_F(RPCAMMInfoHandlerTest, AMMAccountNotFoundMissingAmmField) kAMM_ACCOUNT )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); ASSERT_FALSE(output); @@ -291,7 +295,7 @@ TEST_F(RPCAMMInfoHandlerTest, AMMAccountAmmBlobNotFound) kAMM_ACCOUNT )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); ASSERT_FALSE(output); @@ -330,7 +334,7 @@ TEST_F(RPCAMMInfoHandlerTest, AMMAccountAccBlobNotFound) kAMM_ACCOUNT )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); ASSERT_FALSE(output); @@ -375,7 +379,7 @@ TEST_F(RPCAMMInfoHandlerTest, HappyPathMinimalFirstXRPNoTrustline) kAMM_ACCOUNT )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); auto expectedResult = json::parse(fmt::format( @@ -457,7 +461,7 @@ TEST_F(RPCAMMInfoHandlerTest, HappyPathWithAccount) kAMM_ACCOUNT2 )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); auto const expectedResult = json::parse(fmt::format( @@ -529,7 +533,7 @@ TEST_F(RPCAMMInfoHandlerTest, HappyPathMinimalSecondXRPNoTrustline) kAMM_ACCOUNT )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); auto const expectedResult = json::parse(fmt::format( @@ -599,7 +603,7 @@ TEST_F(RPCAMMInfoHandlerTest, HappyPathNonXRPNoTrustlines) kAMM_ACCOUNT )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); auto const expectedResult = json::parse(fmt::format( @@ -688,7 +692,7 @@ TEST_F(RPCAMMInfoHandlerTest, HappyPathFrozen) kAMM_ACCOUNT )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); auto const expectedResult = json::parse(fmt::format( @@ -778,7 +782,7 @@ TEST_F(RPCAMMInfoHandlerTest, HappyPathFrozenIssuer) kAMM_ACCOUNT )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); auto const expectedResult = json::parse(fmt::format( @@ -860,7 +864,7 @@ TEST_F(RPCAMMInfoHandlerTest, HappyPathWithTrustline) kAMM_ACCOUNT )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); auto expectedResult = json::parse(fmt::format( @@ -937,7 +941,7 @@ TEST_F(RPCAMMInfoHandlerTest, HappyPathWithVoteSlots) kAMM_ACCOUNT )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); auto expectedResult = json::parse(fmt::format( @@ -1030,7 +1034,7 @@ TEST_F(RPCAMMInfoHandlerTest, HappyPathWithAuctionSlot) kAMM_ACCOUNT )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); auto expectedResult = json::parse(fmt::format( @@ -1126,7 +1130,7 @@ TEST_F(RPCAMMInfoHandlerTest, HappyPathWithAssetsMatchingInputOrder) kAMM_ACCOUNT2 )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); auto expectedResult = json::parse(fmt::format( @@ -1236,7 +1240,7 @@ TEST_F(RPCAMMInfoHandlerTest, HappyPathWithAssetsPreservesInputOrder) kAMM_ACCOUNT2 )); - auto const handler = AnyHandler{AMMInfoHandler{backend_}}; + auto const handler = AnyHandler{AMMInfoHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](auto yield) { auto const output = handler.process(kINPUT, Context{yield}); auto expectedResult = json::parse(fmt::format( diff --git a/tests/unit/rpc/handlers/AllHandlerTests.cpp b/tests/unit/rpc/handlers/AllHandlerTests.cpp index d6895bc1..cf82e91b 100644 --- a/tests/unit/rpc/handlers/AllHandlerTests.cpp +++ b/tests/unit/rpc/handlers/AllHandlerTests.cpp @@ -136,10 +136,12 @@ private: HandlerType initHandler() { - if constexpr (std::is_same_v || std::is_same_v) { + if constexpr (std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || + std::is_same_v) { return HandlerType{this->backend_, this->mockAmendmentCenterPtr_}; } else if constexpr (std::is_same_v) { - return HandlerType{this->backend_, this->mockSubscriptionManagerPtr_}; + return HandlerType{this->backend_, this->mockAmendmentCenterPtr_, this->mockSubscriptionManagerPtr_}; } else if constexpr (std::is_same_v) { return HandlerType{ this->backend_, diff --git a/tests/unit/rpc/handlers/BookOffersTests.cpp b/tests/unit/rpc/handlers/BookOffersTests.cpp index 88d3056d..dc158792 100644 --- a/tests/unit/rpc/handlers/BookOffersTests.cpp +++ b/tests/unit/rpc/handlers/BookOffersTests.cpp @@ -17,6 +17,7 @@ */ //============================================================================== +#include "data/AmendmentCenter.hpp" #include "data/Types.hpp" #include "rpc/Errors.hpp" #include "rpc/RPCHelpers.hpp" @@ -24,6 +25,7 @@ #include "rpc/common/Types.hpp" #include "rpc/handlers/BookOffers.hpp" #include "util/HandlerBaseTestFixture.hpp" +#include "util/MockAmendmentCenter.hpp" #include "util/NameGenerator.hpp" #include "util/TestObject.hpp" @@ -86,6 +88,9 @@ struct RPCBookOffersHandlerTest : HandlerBaseTest { { backend_->setRange(10, 300); } + +protected: + StrictMockAmendmentCenterSharedPtr mockAmendmentCenterPtr_; }; struct RPCBookOffersParameterTest : RPCBookOffersHandlerTest, WithParamInterface {}; @@ -93,7 +98,7 @@ struct RPCBookOffersParameterTest : RPCBookOffersHandlerTest, WithParamInterface TEST_P(RPCBookOffersParameterTest, CheckError) { auto bundle = GetParam(); - auto const handler = AnyHandler{BookOffersHandler{backend_}}; + auto const handler = AnyHandler{BookOffersHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](boost::asio::yield_context yield) { auto const output = handler.process(json::parse(bundle.testJson), Context{.yield = yield}); ASSERT_FALSE(output); @@ -511,6 +516,7 @@ struct BookOffersNormalTestBundle { uint32_t ledgerObjectCalls; std::vector mockedOffers; std::string expectedJson; + uint32_t amendmentIsEnabledCalls = 0; }; struct RPCBookOffersNormalPathTest : public RPCBookOffersHandlerTest, @@ -526,6 +532,11 @@ TEST_P(RPCBookOffersNormalPathTest, CheckOutput) auto const ledgerHeader = createLedgerHeader(kLEDGER_HASH, seq); ON_CALL(*backend_, fetchLedgerBySequence(seq, _)).WillByDefault(Return(ledgerHeader)); + EXPECT_CALL(*mockAmendmentCenterPtr_, isEnabled(_, Amendments::fixFrozenLPTokenTransfer, _)) + .Times(bundle.amendmentIsEnabledCalls); + ON_CALL(*mockAmendmentCenterPtr_, isEnabled(_, Amendments::fixFrozenLPTokenTransfer, _)) + .WillByDefault(Return(false)); + // return valid book dir EXPECT_CALL(*backend_, doFetchSuccessorKey).Times(bundle.mockedSuccessors.size()); for (auto const& [key, value] : bundle.mockedSuccessors) { @@ -548,7 +559,7 @@ TEST_P(RPCBookOffersNormalPathTest, CheckOutput) ON_CALL(*backend_, doFetchLedgerObjects).WillByDefault(Return(bbs)); EXPECT_CALL(*backend_, doFetchLedgerObjects).Times(1); - auto const handler = AnyHandler{BookOffersHandler{backend_}}; + auto const handler = AnyHandler{BookOffersHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](boost::asio::yield_context yield) { auto const output = handler.process(json::parse(bundle.inputJson), Context{.yield = yield}); ASSERT_TRUE(output); @@ -963,7 +974,8 @@ generateNormalPathBookOffersTestBundles() kPAYS20_XRP_GETS10_USD_BOOK_DIR, 8, 2 - ) + ), + .amendmentIsEnabledCalls = 1, }, BookOffersNormalTestBundle{ .testName = "PaysXRPGetsUSDWithMultipleOffers", @@ -1059,7 +1071,8 @@ generateNormalPathBookOffersTestBundles() kACCOUNT2, kPAYS20_XRP_GETS10_USD_BOOK_DIR, 2 - ) + ), + .amendmentIsEnabledCalls = 1, }, BookOffersNormalTestBundle{ .testName = "PaysXRPGetsUSDSellingOwnCurrency", @@ -1216,7 +1229,7 @@ TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaIntSequence) }})", kACCOUNT )); - auto const handler = AnyHandler{BookOffersHandler{backend_}}; + auto const handler = AnyHandler{BookOffersHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](boost::asio::yield_context yield) { auto const output = handler.process(kINPUT, Context{.yield = yield}); ASSERT_FALSE(output); @@ -1247,7 +1260,7 @@ TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaSequence) }})", kACCOUNT )); - auto const handler = AnyHandler{BookOffersHandler{backend_}}; + auto const handler = AnyHandler{BookOffersHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](boost::asio::yield_context yield) { auto const output = handler.process(kINPUT, Context{.yield = yield}); ASSERT_FALSE(output); @@ -1280,7 +1293,7 @@ TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaHash) kLEDGER_HASH, kACCOUNT )); - auto const handler = AnyHandler{BookOffersHandler{backend_}}; + auto const handler = AnyHandler{BookOffersHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](boost::asio::yield_context yield) { auto const output = handler.process(kINPUT, Context{.yield = yield}); ASSERT_FALSE(output); @@ -1355,7 +1368,7 @@ TEST_F(RPCBookOffersHandlerTest, Limit) }})", kACCOUNT )); - auto const handler = AnyHandler{BookOffersHandler{backend_}}; + auto const handler = AnyHandler{BookOffersHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](boost::asio::yield_context yield) { auto const output = handler.process(kINPUT, Context{.yield = yield}); ASSERT_TRUE(output); @@ -1429,7 +1442,7 @@ TEST_F(RPCBookOffersHandlerTest, LimitMoreThanMax) kACCOUNT, BookOffersHandler::kLIMIT_MAX + 1 )); - auto const handler = AnyHandler{BookOffersHandler{backend_}}; + auto const handler = AnyHandler{BookOffersHandler{backend_, mockAmendmentCenterPtr_}}; runSpawn([&](boost::asio::yield_context yield) { auto const output = handler.process(kINPUT, Context{.yield = yield}); ASSERT_TRUE(output); diff --git a/tests/unit/rpc/handlers/LedgerTests.cpp b/tests/unit/rpc/handlers/LedgerTests.cpp index 96d9b1a3..28e9e5f6 100644 --- a/tests/unit/rpc/handlers/LedgerTests.cpp +++ b/tests/unit/rpc/handlers/LedgerTests.cpp @@ -25,6 +25,7 @@ #include "rpc/common/Types.hpp" #include "rpc/handlers/Ledger.hpp" #include "util/HandlerBaseTestFixture.hpp" +#include "util/MockAmendmentCenter.hpp" #include "util/NameGenerator.hpp" #include "util/TestObject.hpp" @@ -68,6 +69,9 @@ struct RPCLedgerHandlerTest : HandlerBaseTest { { backend_->setRange(kRANGE_MIN, kRANGE_MAX); } + +protected: + StrictMockAmendmentCenterSharedPtr mockAmendmentCenterPtr_; }; struct LedgerParamTestCaseBundle { @@ -182,7 +186,7 @@ TEST_P(LedgerParameterTest, InvalidParams) { auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -198,7 +202,7 @@ TEST_F(RPCLedgerHandlerTest, LedgerNotExistViaIntSequence) ON_CALL(*backend_, fetchLedgerBySequence(kRANGE_MAX, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse(fmt::format( R"({{ "ledger_index": {} @@ -219,7 +223,7 @@ TEST_F(RPCLedgerHandlerTest, LedgerNotExistViaStringSequence) ON_CALL(*backend_, fetchLedgerBySequence(kRANGE_MAX, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse(fmt::format( R"({{ "ledger_index": "{}" @@ -240,7 +244,7 @@ TEST_F(RPCLedgerHandlerTest, LedgerNotExistViaHash) ON_CALL(*backend_, fetchLedgerByHash(ripple::uint256{kLEDGER_HASH}, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse(fmt::format( R"({{ "ledger_hash": "{}" @@ -283,7 +287,7 @@ TEST_F(RPCLedgerHandlerTest, Default) ON_CALL(*backend_, fetchLedgerBySequence(kRANGE_MAX, _)).WillByDefault(Return(ledgerHeader)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse("{}"); auto output = handler.process(req, Context{yield}); ASSERT_TRUE(output); @@ -300,7 +304,7 @@ TEST_F(RPCLedgerHandlerTest, ConditionallyNotSupportedFieldsDefaultValue) EXPECT_CALL(*backend_, fetchLedgerBySequence(kRANGE_MAX, _)).WillRepeatedly(Return(ledgerHeader)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "full": false, @@ -320,7 +324,7 @@ TEST_F(RPCLedgerHandlerTest, QueryViaLedgerIndex) ON_CALL(*backend_, fetchLedgerBySequence(15, _)).WillByDefault(Return(ledgerHeader)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse(R"({"ledger_index": 15})"); auto output = handler.process(req, Context{yield}); ASSERT_TRUE(output); @@ -335,7 +339,7 @@ TEST_F(RPCLedgerHandlerTest, QueryViaLedgerHash) ON_CALL(*backend_, fetchLedgerByHash(ripple::uint256{kINDEX1}, _)).WillByDefault(Return(ledgerHeader)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse(fmt::format(R"({{"ledger_hash": "{}" }})", kINDEX1)); auto output = handler.process(req, Context{yield}); ASSERT_TRUE(output); @@ -361,7 +365,7 @@ TEST_F(RPCLedgerHandlerTest, BinaryTrue) ON_CALL(*backend_, fetchLedgerBySequence(kRANGE_MAX, _)).WillByDefault(Return(ledgerHeader)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "binary": true @@ -409,7 +413,7 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandBinary) ON_CALL(*backend_, fetchAllTransactionsInLedger(kRANGE_MAX, _)).WillByDefault(Return(std::vector{t1, t1})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "binary": true, @@ -459,7 +463,7 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandBinaryV2) EXPECT_CALL(*backend_, fetchAllTransactionsInLedger(kRANGE_MAX, _)).WillOnce(Return(std::vector{t1, t1})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "binary": true, @@ -547,7 +551,7 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandNotBinary) ON_CALL(*backend_, fetchAllTransactionsInLedger(kRANGE_MAX, _)).WillByDefault(Return(std::vector{t1})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "binary": false, @@ -645,7 +649,7 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandNotBinaryV2) EXPECT_CALL(*backend_, fetchAllTransactionsInLedger(kRANGE_MAX, _)).WillOnce(Return(std::vector{t1})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "binary": false, @@ -678,7 +682,7 @@ TEST_F(RPCLedgerHandlerTest, TwoRequestInARowTransactionsExpandNotBinaryV2) EXPECT_CALL(*backend_, fetchAllTransactionsInLedger(kRANGE_MAX - 1, _)).WillOnce(Return(std::vector{t1})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "binary": false, @@ -718,7 +722,7 @@ TEST_F(RPCLedgerHandlerTest, TransactionsNotExpand) .WillByDefault(Return(std::vector{ripple::uint256{kINDEX1}, ripple::uint256{kINDEX2}})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "transactions": true @@ -776,7 +780,7 @@ TEST_F(RPCLedgerHandlerTest, DiffNotBinary) ON_CALL(*backend_, fetchLedgerDiff(kRANGE_MAX, _)).WillByDefault(Return(los)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "diff": true @@ -820,7 +824,7 @@ TEST_F(RPCLedgerHandlerTest, DiffBinary) ON_CALL(*backend_, fetchLedgerDiff(kRANGE_MAX, _)).WillByDefault(Return(los)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "diff": true, @@ -907,7 +911,7 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsEmtpy) ON_CALL(*backend_, fetchAllTransactionsInLedger(kRANGE_MAX, _)).WillByDefault(Return(std::vector{t1})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "binary": false, @@ -1015,7 +1019,7 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsTrueBinaryFalse) ON_CALL(*backend_, fetchAllTransactionsInLedger(kRANGE_MAX, _)).WillByDefault(Return(std::vector{tx})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "binary": false, @@ -1084,7 +1088,7 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsTrueBinaryTrue) ON_CALL(*backend_, fetchAllTransactionsInLedger(kRANGE_MAX, _)).WillByDefault(Return(std::vector{tx})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "binary": true, @@ -1117,7 +1121,7 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsIssuerIsSelf) ON_CALL(*backend_, fetchAllTransactionsInLedger(kRANGE_MAX, _)).WillByDefault(Return(std::vector{tx})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "binary": true, @@ -1186,7 +1190,7 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsNotEnoughForReserve) ON_CALL(*backend_, fetchAllTransactionsInLedger(kRANGE_MAX, _)).WillByDefault(Return(std::vector{tx})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "binary": true, @@ -1232,7 +1236,7 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsNotXRP) ON_CALL(*backend_, fetchAllTransactionsInLedger(kRANGE_MAX, _)).WillByDefault(Return(std::vector{tx})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "binary": true, @@ -1295,7 +1299,7 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsIgnoreFreezeLine) ON_CALL(*backend_, fetchAllTransactionsInLedger(kRANGE_MAX, _)).WillByDefault(Return(std::vector{tx})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{backend_}}; + auto const handler = AnyHandler{LedgerHandler{backend_, mockAmendmentCenterPtr_}}; auto const req = json::parse( R"({ "binary": true, diff --git a/tests/unit/rpc/handlers/SubscribeTests.cpp b/tests/unit/rpc/handlers/SubscribeTests.cpp index 312bdf6d..ba67c058 100644 --- a/tests/unit/rpc/handlers/SubscribeTests.cpp +++ b/tests/unit/rpc/handlers/SubscribeTests.cpp @@ -24,6 +24,7 @@ #include "rpc/common/Types.hpp" #include "rpc/handlers/Subscribe.hpp" #include "util/HandlerBaseTestFixture.hpp" +#include "util/MockAmendmentCenter.hpp" #include "util/MockSubscriptionManager.hpp" #include "util/MockWsBase.hpp" #include "util/NameGenerator.hpp" @@ -72,6 +73,7 @@ protected: web::SubscriptionContextPtr session_ = std::make_shared(); MockSession* mockSession_ = dynamic_cast(session_.get()); StrictMockSubscriptionManagerSharedPtr mockSubscriptionManagerPtr_; + StrictMockAmendmentCenterSharedPtr mockAmendmentCenterPtr_; }; struct SubscribeParamTestCaseBundle { @@ -601,7 +603,8 @@ TEST_P(SubscribeParameterTest, InvalidParams) { auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{backend_, mockSubscriptionManagerPtr_}}; + auto const handler = + AnyHandler{SubscribeHandler{backend_, mockAmendmentCenterPtr_, mockSubscriptionManagerPtr_}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -614,7 +617,8 @@ TEST_P(SubscribeParameterTest, InvalidParams) TEST_F(RPCSubscribeHandlerTest, EmptyResponse) { runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{backend_, mockSubscriptionManagerPtr_}}; + auto const handler = + AnyHandler{SubscribeHandler{backend_, mockAmendmentCenterPtr_, mockSubscriptionManagerPtr_}}; EXPECT_CALL(*mockSession_, setApiSubversion(0)); auto const output = handler.process(json::parse(R"({})"), Context{yield, session_}); ASSERT_TRUE(output); @@ -631,7 +635,8 @@ TEST_F(RPCSubscribeHandlerTest, StreamsWithoutLedger) })" ); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{backend_, mockSubscriptionManagerPtr_}}; + auto const handler = + AnyHandler{SubscribeHandler{backend_, mockAmendmentCenterPtr_, mockSubscriptionManagerPtr_}}; EXPECT_CALL(*mockSubscriptionManagerPtr_, subTransactions); EXPECT_CALL(*mockSubscriptionManagerPtr_, subValidation); EXPECT_CALL(*mockSubscriptionManagerPtr_, subManifest); @@ -664,7 +669,8 @@ TEST_F(RPCSubscribeHandlerTest, StreamsLedger) })" ); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{backend_, mockSubscriptionManagerPtr_}}; + auto const handler = + AnyHandler{SubscribeHandler{backend_, mockAmendmentCenterPtr_, mockSubscriptionManagerPtr_}}; EXPECT_CALL(*mockSubscriptionManagerPtr_, subLedger) .WillOnce(testing::Return(boost::json::parse(kEXPECTED_OUTPUT).as_object())); @@ -687,7 +693,8 @@ TEST_F(RPCSubscribeHandlerTest, Accounts) kACCOUNT2 )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{backend_, mockSubscriptionManagerPtr_}}; + auto const handler = + AnyHandler{SubscribeHandler{backend_, mockAmendmentCenterPtr_, mockSubscriptionManagerPtr_}}; EXPECT_CALL(*mockSubscriptionManagerPtr_, subAccount(getAccountIdWithString(kACCOUNT), session_)); EXPECT_CALL(*mockSubscriptionManagerPtr_, subAccount(getAccountIdWithString(kACCOUNT2), session_)).Times(2); @@ -709,7 +716,8 @@ TEST_F(RPCSubscribeHandlerTest, AccountsProposed) kACCOUNT2 )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{backend_, mockSubscriptionManagerPtr_}}; + auto const handler = + AnyHandler{SubscribeHandler{backend_, mockAmendmentCenterPtr_, mockSubscriptionManagerPtr_}}; EXPECT_CALL(*mockSubscriptionManagerPtr_, subProposedAccount(getAccountIdWithString(kACCOUNT), session_)); EXPECT_CALL(*mockSubscriptionManagerPtr_, subProposedAccount(getAccountIdWithString(kACCOUNT2), session_)) @@ -743,7 +751,8 @@ TEST_F(RPCSubscribeHandlerTest, JustBooks) kACCOUNT )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{backend_, mockSubscriptionManagerPtr_}}; + auto const handler = + AnyHandler{SubscribeHandler{backend_, mockAmendmentCenterPtr_, mockSubscriptionManagerPtr_}}; EXPECT_CALL(*mockSubscriptionManagerPtr_, subBook); EXPECT_CALL(*mockSession_, setApiSubversion(0)); auto const output = handler.process(input, Context{yield, session_}); @@ -775,7 +784,8 @@ TEST_F(RPCSubscribeHandlerTest, BooksBothSet) kACCOUNT )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{backend_, mockSubscriptionManagerPtr_}}; + auto const handler = + AnyHandler{SubscribeHandler{backend_, mockAmendmentCenterPtr_, mockSubscriptionManagerPtr_}}; EXPECT_CALL(*mockSubscriptionManagerPtr_, subBook).Times(2); EXPECT_CALL(*mockSession_, setApiSubversion(0)); auto const output = handler.process(input, Context{yield, session_}); @@ -940,7 +950,8 @@ TEST_F(RPCSubscribeHandlerTest, BooksBothSnapshotSet) kACCOUNT ); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{backend_, mockSubscriptionManagerPtr_}}; + auto const handler = + AnyHandler{SubscribeHandler{backend_, mockAmendmentCenterPtr_, mockSubscriptionManagerPtr_}}; EXPECT_CALL(*mockSubscriptionManagerPtr_, subBook).Times(2); EXPECT_CALL(*mockSession_, setApiSubversion(0)); auto const output = handler.process(input, Context{yield, session_}); @@ -1083,7 +1094,8 @@ TEST_F(RPCSubscribeHandlerTest, BooksBothUnsetSnapshotSet) ); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{backend_, mockSubscriptionManagerPtr_}}; + auto const handler = + AnyHandler{SubscribeHandler{backend_, mockAmendmentCenterPtr_, mockSubscriptionManagerPtr_}}; EXPECT_CALL(*mockSubscriptionManagerPtr_, subBook); EXPECT_CALL(*mockSession_, setApiSubversion(0)); auto const output = handler.process(input, Context{yield, session_}); @@ -1102,7 +1114,8 @@ TEST_F(RPCSubscribeHandlerTest, APIVersion) ); auto const apiVersion = 2; runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{backend_, mockSubscriptionManagerPtr_}}; + auto const handler = + AnyHandler{SubscribeHandler{backend_, mockAmendmentCenterPtr_, mockSubscriptionManagerPtr_}}; EXPECT_CALL(*mockSubscriptionManagerPtr_, subProposedTransactions); EXPECT_CALL(*mockSession_, setApiSubversion(apiVersion)); auto const output =