Skip to content

Commit

Permalink
feat: LPT freeze (#1840)
Browse files Browse the repository at this point in the history
Fixes #1827
  • Loading branch information
shawnxie999 authored Feb 24, 2025
1 parent f577139 commit c9e8330
Show file tree
Hide file tree
Showing 30 changed files with 765 additions and 139 deletions.
6 changes: 4 additions & 2 deletions src/app/ClioApplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ ClioApplication::run(bool const useNgWebServer)
// Interface to the database
auto backend = data::makeBackend(config_);

auto const amendmentCenter = std::make_shared<data::AmendmentCenter const>(backend);

{
auto const migrationInspector = migration::makeMigrationInspector(config_, backend);
// Check if any migration is blocking Clio server starting.
Expand All @@ -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();
Expand All @@ -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<data::AmendmentCenter const>(backend);

auto const handlerProvider = std::make_shared<rpc::impl::ProductionHandlerProvider const>(
config_, backend, subscriptions, balancer, etl, amendmentCenter, counters
);
Expand Down
1 change: 1 addition & 0 deletions src/data/AmendmentCenter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ struct Amendments {
REGISTER(Credentials);
REGISTER(DynamicNFT);
REGISTER(PermissionedDomains);
REGISTER(fixFrozenLPTokenTransfer);

// Obsolete but supported by libxrpl
REGISTER(CryptoConditionsSuite);
Expand Down
2 changes: 1 addition & 1 deletion src/feed/SubscriptionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 12 additions & 3 deletions src/feed/SubscriptionManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#pragma once

#include "data/AmendmentCenterInterface.hpp"
#include "data/BackendInterface.hpp"
#include "data/Types.hpp"
#include "feed/SubscriptionManagerInterface.hpp"
Expand Down Expand Up @@ -60,6 +61,7 @@ namespace feed {
*/
class SubscriptionManager : public SubscriptionManagerInterface {
std::shared_ptr<data::BackendInterface const> backend_;
std::shared_ptr<data::AmendmentCenterInterface const> amendmentCenter_;
util::async::AnyExecutionContext ctx_;
impl::ForwardFeed manifestFeed_;
impl::ForwardFeed validationsFeed_;
Expand All @@ -74,33 +76,40 @@ class SubscriptionManager : public SubscriptionManagerInterface {
*
* @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<SubscriptionManager>
makeSubscriptionManager(
util::config::ClioConfigDefinition const& config,
std::shared_ptr<data::BackendInterface const> const& backend
std::shared_ptr<data::BackendInterface const> const& backend,
std::shared_ptr<data::AmendmentCenterInterface const> const& amendmentCenter
)
{
auto const workersNum = config.get<uint64_t>("subscription_workers");

util::Logger const logger{"Subscriptions"};
LOG(logger.info()) << "Starting subscription manager with " << workersNum << " workers";

return std::make_shared<feed::SubscriptionManager>(util::async::PoolExecutionContext(workersNum), backend);
return std::make_shared<feed::SubscriptionManager>(
util::async::PoolExecutionContext(workersNum), backend, amendmentCenter
);
}

/**
* @brief Construct a new Subscription Manager object
*
* @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<data::BackendInterface const> const& backend
std::shared_ptr<data::BackendInterface const> const& backend,
std::shared_ptr<data::AmendmentCenterInterface const> const& amendmentCenter
)
: backend_(backend)
, amendmentCenter_(amendmentCenter)
, ctx_(std::move(executor))
, manifestFeed_(ctx_, "manifest")
, validationsFeed_(ctx_, "validations")
Expand Down
6 changes: 4 additions & 2 deletions src/feed/impl/TransactionFeed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -174,7 +175,8 @@ void
TransactionFeed::pub(
data::TransactionAndMetadata const& txMeta,
ripple::LedgerHeader const& lgrInfo,
std::shared_ptr<data::BackendInterface const> const& backend
std::shared_ptr<data::BackendInterface const> const& backend,
std::shared_ptr<data::AmendmentCenterInterface const> const& amendmentCenter
)
{
auto [tx, meta] = rpc::deserializeTxPlusMeta(txMeta, lgrInfo.seq);
Expand All @@ -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);
Expand Down
4 changes: 3 additions & 1 deletion src/feed/impl/TransactionFeed.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#pragma once

#include "data/AmendmentCenterInterface.hpp"
#include "data/BackendInterface.hpp"
#include "data/Types.hpp"
#include "feed/Types.hpp"
Expand Down Expand Up @@ -180,7 +181,8 @@ class TransactionFeed {
void
pub(data::TransactionAndMetadata const& txMeta,
ripple::LedgerHeader const& lgrInfo,
std::shared_ptr<data::BackendInterface const> const& backend);
std::shared_ptr<data::BackendInterface const> const& backend,
std::shared_ptr<data::AmendmentCenterInterface const> const& amendmentCenter);

/**
* @brief Get the number of subscribers of the transaction feed.
Expand Down
15 changes: 10 additions & 5 deletions src/rpc/AMMHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace rpc {
std::pair<ripple::STAmount, ripple::STAmount>
getAmmPoolHolds(
BackendInterface const& backend,
data::AmendmentCenterInterface const& amendmentCenter,
std::uint32_t sequence,
ripple::AccountID const& ammAccountID,
ripple::Issue const& issue1,
Expand All @@ -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);
}

Expand All @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/rpc/AMMHelpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#pragma once

#include "data/AmendmentCenterInterface.hpp"
#include "data/BackendInterface.hpp"

#include <boost/asio/spawn.hpp>
Expand All @@ -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
Expand All @@ -48,6 +50,7 @@ namespace rpc {
std::pair<ripple::STAmount, ripple::STAmount>
getAmmPoolHolds(
BackendInterface const& backend,
data::AmendmentCenterInterface const& amendmentCenter,
std::uint32_t sequence,
ripple::AccountID const& ammAccountID,
ripple::Issue const& issue1,
Expand Down
118 changes: 115 additions & 3 deletions src/rpc/RPCHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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)};

Expand Down Expand Up @@ -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<ripple::Issue>(),
ammSle[ripple::sfAsset2].get<ripple::Issue>(),
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,
Expand Down Expand Up @@ -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
)
Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit c9e8330

Please sign in to comment.