mirror of
https://github.com/XRPLF/clio.git
synced 2025-12-06 17:27:58 +00:00
@@ -902,6 +902,26 @@ isGlobalFrozen(
|
|||||||
return sle.isFlag(ripple::lsfGlobalFreeze);
|
return sle.isFlag(ripple::lsfGlobalFreeze);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
fetchAndCheckAnyFlagsExists(
|
||||||
|
BackendInterface const& backend,
|
||||||
|
std::uint32_t sequence,
|
||||||
|
ripple::Keylet const& keylet,
|
||||||
|
std::vector<std::uint32_t> const& flags,
|
||||||
|
boost::asio::yield_context yield
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto const blob = backend.fetchLedgerObject(keylet.key, sequence, yield);
|
||||||
|
|
||||||
|
if (!blob)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ripple::SerialIter it{blob->data(), blob->size()};
|
||||||
|
ripple::SLE const sle{it, keylet.key};
|
||||||
|
|
||||||
|
return std::ranges::any_of(flags, [sle](std::uint32_t flag) { return sle.isFlag(flag); });
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
isFrozen(
|
isFrozen(
|
||||||
BackendInterface const& backend,
|
BackendInterface const& backend,
|
||||||
@@ -915,35 +935,43 @@ isFrozen(
|
|||||||
if (ripple::isXRP(currency))
|
if (ripple::isXRP(currency))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto key = ripple::keylet::account(issuer).key;
|
if (fetchAndCheckAnyFlagsExists(
|
||||||
auto blob = backend.fetchLedgerObject(key, sequence, yield);
|
backend, sequence, ripple::keylet::account(issuer), {ripple::lsfGlobalFreeze}, yield
|
||||||
|
))
|
||||||
if (!blob)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ripple::SerialIter it{blob->data(), blob->size()};
|
|
||||||
ripple::SLE const sle{it, key};
|
|
||||||
|
|
||||||
if (sle.isFlag(ripple::lsfGlobalFreeze))
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (issuer != account) {
|
auto const trustLineKeylet = ripple::keylet::line(account, issuer, currency);
|
||||||
key = ripple::keylet::line(account, issuer, currency).key;
|
return issuer != account &&
|
||||||
blob = backend.fetchLedgerObject(key, sequence, yield);
|
fetchAndCheckAnyFlagsExists(
|
||||||
|
backend,
|
||||||
|
sequence,
|
||||||
|
trustLineKeylet,
|
||||||
|
{(issuer > account) ? ripple::lsfHighFreeze : ripple::lsfLowFreeze},
|
||||||
|
yield
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!blob)
|
bool
|
||||||
return false;
|
isDeepFrozen(
|
||||||
|
BackendInterface const& backend,
|
||||||
|
std::uint32_t sequence,
|
||||||
|
ripple::AccountID const& account,
|
||||||
|
ripple::Currency const& currency,
|
||||||
|
ripple::AccountID const& issuer,
|
||||||
|
boost::asio::yield_context yield
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (ripple::isXRP(currency))
|
||||||
|
return false;
|
||||||
|
|
||||||
ripple::SerialIter issuerIt{blob->data(), blob->size()};
|
if (issuer == account)
|
||||||
ripple::SLE const issuerLine{issuerIt, key};
|
return false;
|
||||||
|
|
||||||
auto frozen = (issuer > account) ? ripple::lsfHighFreeze : ripple::lsfLowFreeze;
|
auto const trustLineKeylet = ripple::keylet::line(account, issuer, currency);
|
||||||
|
|
||||||
if (issuerLine.isFlag(frozen))
|
return fetchAndCheckAnyFlagsExists(
|
||||||
return true;
|
backend, sequence, trustLineKeylet, {ripple::lsfHighDeepFreeze, ripple::lsfLowDeepFreeze}, yield
|
||||||
}
|
);
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -1040,7 +1068,9 @@ ammAccountHolds(
|
|||||||
ripple::SerialIter it{blob->data(), blob->size()};
|
ripple::SerialIter it{blob->data(), blob->size()};
|
||||||
ripple::SLE const sle{it, key};
|
ripple::SLE const sle{it, key};
|
||||||
|
|
||||||
if (zeroIfFrozen && isFrozen(backend, sequence, account, currency, issuer, yield)) {
|
if (zeroIfFrozen &&
|
||||||
|
(isFrozen(backend, sequence, account, currency, issuer, yield) ||
|
||||||
|
isDeepFrozen(backend, sequence, account, currency, issuer, yield))) {
|
||||||
amount.setIssue(ripple::Issue(currency, issuer));
|
amount.setIssue(ripple::Issue(currency, issuer));
|
||||||
amount.clear();
|
amount.clear();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -428,6 +428,49 @@ isFrozen(
|
|||||||
boost::asio::yield_context yield
|
boost::asio::yield_context yield
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fetches a ledger object and checks if any of the specified flag is set on the account.
|
||||||
|
*
|
||||||
|
* @param backend The backend to use
|
||||||
|
* @param sequence The sequence
|
||||||
|
* @param keylet The keylet representing the object
|
||||||
|
* @param flags The flags to check on the fetched `SLE`.
|
||||||
|
* @param yield The coroutine context
|
||||||
|
* @return true if any of the flag in flags are set for this account; false otherwise
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
fetchAndCheckAnyFlagsExists(
|
||||||
|
BackendInterface const& backend,
|
||||||
|
std::uint32_t sequence,
|
||||||
|
ripple::Keylet const& keylet,
|
||||||
|
std::vector<std::uint32_t> const& flags,
|
||||||
|
boost::asio::yield_context yield
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Whether the trustline is deep frozen.
|
||||||
|
*
|
||||||
|
* For deep freeze, (unlike regular freeze) we do not care which account has the high/low deep freeze flag.
|
||||||
|
* We only care about if the trustline is deep frozen or not.
|
||||||
|
*
|
||||||
|
* @param backend The backend to use
|
||||||
|
* @param sequence The sequence
|
||||||
|
* @param account The account
|
||||||
|
* @param currency The currency
|
||||||
|
* @param issuer The issuer
|
||||||
|
* @param yield The coroutine context
|
||||||
|
* @return true if the account is deep frozen; false otherwise
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
isDeepFrozen(
|
||||||
|
BackendInterface const& backend,
|
||||||
|
std::uint32_t sequence,
|
||||||
|
ripple::AccountID const& account,
|
||||||
|
ripple::Currency const& currency,
|
||||||
|
ripple::AccountID const& issuer,
|
||||||
|
boost::asio::yield_context yield
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the account that owns a LPToken is frozen for the assets in the pool
|
* @brief Whether the account that owns a LPToken is frozen for the assets in the pool
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ AccountLinesHandler::addLine(
|
|||||||
bool const lineNoRipplePeer = (flags & (not viewLowest ? ripple::lsfLowNoRipple : ripple::lsfHighNoRipple)) != 0u;
|
bool const lineNoRipplePeer = (flags & (not viewLowest ? ripple::lsfLowNoRipple : ripple::lsfHighNoRipple)) != 0u;
|
||||||
bool const lineFreeze = (flags & (viewLowest ? ripple::lsfLowFreeze : ripple::lsfHighFreeze)) != 0u;
|
bool const lineFreeze = (flags & (viewLowest ? ripple::lsfLowFreeze : ripple::lsfHighFreeze)) != 0u;
|
||||||
bool const lineFreezePeer = (flags & (not viewLowest ? ripple::lsfLowFreeze : ripple::lsfHighFreeze)) != 0u;
|
bool const lineFreezePeer = (flags & (not viewLowest ? ripple::lsfLowFreeze : ripple::lsfHighFreeze)) != 0u;
|
||||||
|
bool const lineDeepFreeze = (flags & (viewLowest ? ripple::lsfLowDeepFreeze : ripple::lsfHighFreeze)) != 0u;
|
||||||
|
bool const lineDeepFreezePeer = (flags & (not viewLowest ? ripple::lsfLowDeepFreeze : ripple::lsfHighFreeze)) != 0u;
|
||||||
|
|
||||||
ripple::STAmount const& saBalance = balance;
|
ripple::STAmount const& saBalance = balance;
|
||||||
ripple::STAmount const& saLimit = lineLimit;
|
ripple::STAmount const& saLimit = lineLimit;
|
||||||
@@ -112,6 +114,12 @@ AccountLinesHandler::addLine(
|
|||||||
if (lineFreezePeer)
|
if (lineFreezePeer)
|
||||||
line.freezePeer = true;
|
line.freezePeer = true;
|
||||||
|
|
||||||
|
if (lineDeepFreeze)
|
||||||
|
line.deepFreeze = true;
|
||||||
|
|
||||||
|
if (lineDeepFreezePeer)
|
||||||
|
line.deepFreezePeer = true;
|
||||||
|
|
||||||
line.noRipple = lineNoRipple;
|
line.noRipple = lineNoRipple;
|
||||||
line.noRipplePeer = lineNoRipplePeer;
|
line.noRipplePeer = lineNoRipplePeer;
|
||||||
lines.push_back(line);
|
lines.push_back(line);
|
||||||
@@ -264,6 +272,12 @@ tag_invoke(
|
|||||||
if (line.freezePeer)
|
if (line.freezePeer)
|
||||||
obj[JS(freeze_peer)] = *(line.freezePeer);
|
obj[JS(freeze_peer)] = *(line.freezePeer);
|
||||||
|
|
||||||
|
if (line.deepFreeze)
|
||||||
|
obj[JS(deep_freeze)] = *(line.deepFreeze);
|
||||||
|
|
||||||
|
if (line.deepFreezePeer)
|
||||||
|
obj[JS(deep_freeze_peer)] = *(line.deepFreezePeer);
|
||||||
|
|
||||||
jv = std::move(obj);
|
jv = std::move(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ public:
|
|||||||
std::optional<bool> peerAuthorized;
|
std::optional<bool> peerAuthorized;
|
||||||
std::optional<bool> freeze;
|
std::optional<bool> freeze;
|
||||||
std::optional<bool> freezePeer;
|
std::optional<bool> freezePeer;
|
||||||
|
std::optional<bool> deepFreeze;
|
||||||
|
std::optional<bool> deepFreezePeer;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <optional>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
@@ -67,6 +68,8 @@ constexpr auto kACCOUNT2 = "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun";
|
|||||||
constexpr auto kINDEX1 = "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC321";
|
constexpr auto kINDEX1 = "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC321";
|
||||||
constexpr auto kINDEX2 = "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC322";
|
constexpr auto kINDEX2 = "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC322";
|
||||||
constexpr auto kTXN_ID = "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC321";
|
constexpr auto kTXN_ID = "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC321";
|
||||||
|
constexpr auto kLEDGER_SEQ_OBJECT = 50;
|
||||||
|
constexpr auto kCURRENCY = "0158415500000000C1F76FF6ECB0BAC600000000";
|
||||||
constexpr auto kAMM_ACCOUNT = "rnW8FAPgpQgA6VoESnVrUVJHBdq9QAtRZs";
|
constexpr auto kAMM_ACCOUNT = "rnW8FAPgpQgA6VoESnVrUVJHBdq9QAtRZs";
|
||||||
constexpr auto kISSUER = "rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD";
|
constexpr auto kISSUER = "rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD";
|
||||||
constexpr auto kLPTOKEN_CURRENCY = "037C35306B24AAB7FF90848206E003279AA47090";
|
constexpr auto kLPTOKEN_CURRENCY = "037C35306B24AAB7FF90848206E003279AA47090";
|
||||||
@@ -78,6 +81,7 @@ class RPCHelpersTest : public util::prometheus::WithPrometheus, public MockBacke
|
|||||||
void
|
void
|
||||||
SetUp() override
|
SetUp() override
|
||||||
{
|
{
|
||||||
|
backend_->setRange(10, 300);
|
||||||
SyncAsioContextTest::SetUp();
|
SyncAsioContextTest::SetUp();
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
@@ -558,6 +562,277 @@ TEST_F(RPCHelpersTest, ParseIssue)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, FetchAndCheckAnyFlagExists_BlobDoesNotExist)
|
||||||
|
{
|
||||||
|
auto const account = getAccountIdWithString(kACCOUNT);
|
||||||
|
auto const issuerKey = ripple::keylet::account(account);
|
||||||
|
|
||||||
|
// returns empty blob
|
||||||
|
ON_CALL(*backend_, doFetchLedgerObject(issuerKey.key, kLEDGER_SEQ_OBJECT, _))
|
||||||
|
.WillByDefault(Return(std::optional<Blob>{}));
|
||||||
|
|
||||||
|
runSpawn([&](boost::asio::yield_context yield) {
|
||||||
|
// return false: blob doesn't exist
|
||||||
|
EXPECT_FALSE(
|
||||||
|
fetchAndCheckAnyFlagsExists(*backend_, kLEDGER_SEQ_OBJECT, issuerKey, {ripple::lsfHighDeepFreeze}, yield)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, FetchAndCheckAnyFlagExistsBlobExists_AccountWithCorrectFlag)
|
||||||
|
{
|
||||||
|
auto const account = getAccountIdWithString(kACCOUNT);
|
||||||
|
auto const issuerKey = ripple::keylet::account(account);
|
||||||
|
|
||||||
|
// create account with highDeepFreeze Flag
|
||||||
|
auto const accountObject = createAccountRootObject(kACCOUNT, ripple::lsfHighDeepFreeze, 1, 10, 2, kTXN_ID, 3);
|
||||||
|
|
||||||
|
ON_CALL(*backend_, doFetchLedgerObject(issuerKey.key, kLEDGER_SEQ_OBJECT, _))
|
||||||
|
.WillByDefault(Return(accountObject.getSerializer().peekData()));
|
||||||
|
|
||||||
|
runSpawn([&](boost::asio::yield_context yield) {
|
||||||
|
// returns true: accountObject has the highDeepFreeze flag
|
||||||
|
EXPECT_TRUE(
|
||||||
|
fetchAndCheckAnyFlagsExists(*backend_, kLEDGER_SEQ_OBJECT, issuerKey, {ripple::lsfHighDeepFreeze}, yield)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, FetchAndCheckAnyFlagExistsBlobExists_AccountFlagDoesNotExist)
|
||||||
|
{
|
||||||
|
auto const account = getAccountIdWithString(kACCOUNT);
|
||||||
|
auto const issuerKey = ripple::keylet::account(account);
|
||||||
|
|
||||||
|
// create account with highDeepFreeze Flag
|
||||||
|
auto const accountObject = createAccountRootObject(kACCOUNT, ripple::lsfLowDeepFreeze, 1, 10, 2, kTXN_ID, 3);
|
||||||
|
|
||||||
|
ON_CALL(*backend_, doFetchLedgerObject(issuerKey.key, kLEDGER_SEQ_OBJECT, _))
|
||||||
|
.WillByDefault(Return(accountObject.getSerializer().peekData()));
|
||||||
|
|
||||||
|
runSpawn([&](boost::asio::yield_context yield) {
|
||||||
|
// returns false: accountObject has the lowDeepFreeze flag
|
||||||
|
EXPECT_FALSE(
|
||||||
|
fetchAndCheckAnyFlagsExists(*backend_, kLEDGER_SEQ_OBJECT, issuerKey, {ripple::lsfHighDeepFreeze}, yield)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, isGlobalFrozen_AccountIsGlobalFrozen)
|
||||||
|
{
|
||||||
|
auto const account = getAccountIdWithString(kACCOUNT);
|
||||||
|
auto const issuerKey = ripple::keylet::account(account);
|
||||||
|
|
||||||
|
auto const accountObject = createAccountRootObject(kACCOUNT, ripple::lsfGlobalFreeze, 1, 10, 2, kTXN_ID, 3);
|
||||||
|
|
||||||
|
ON_CALL(*backend_, doFetchLedgerObject(issuerKey.key, kLEDGER_SEQ_OBJECT, _))
|
||||||
|
.WillByDefault(Return(accountObject.getSerializer().peekData()));
|
||||||
|
|
||||||
|
runSpawn([&](boost::asio::yield_context yield) {
|
||||||
|
// returns false: accountObject has the lowDeepFreeze flag
|
||||||
|
EXPECT_TRUE(isGlobalFrozen(*backend_, kLEDGER_SEQ_OBJECT, account, yield));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, isDeepFrozen_TrustLineIsDeepFrozen)
|
||||||
|
{
|
||||||
|
auto const account = getAccountIdWithString(kACCOUNT);
|
||||||
|
auto const account2 = getAccountIdWithString(kACCOUNT2);
|
||||||
|
|
||||||
|
// create a trustline between account and account2 and is deep frozen
|
||||||
|
auto const trustLineKey = ripple::keylet::line(account, account2, ripple::Currency{kCURRENCY}).key;
|
||||||
|
auto const trustlineDeepFrozen = createRippleStateLedgerObject(
|
||||||
|
"USD", kACCOUNT, 8, kACCOUNT, 1000, kACCOUNT2, 2000, kINDEX1, 2, ripple::lsfLowDeepFreeze
|
||||||
|
);
|
||||||
|
|
||||||
|
ON_CALL(*backend_, doFetchLedgerObject(trustLineKey, kLEDGER_SEQ_OBJECT, _))
|
||||||
|
.WillByDefault(Return(trustlineDeepFrozen.getSerializer().peekData()));
|
||||||
|
|
||||||
|
runSpawn([&](boost::asio::yield_context yield) {
|
||||||
|
EXPECT_TRUE(isDeepFrozen(*backend_, kLEDGER_SEQ_OBJECT, account, ripple::Currency{kCURRENCY}, account2, yield));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, isDeepFrozen_TrustLineIsNotDeepFrozen)
|
||||||
|
{
|
||||||
|
auto const account = getAccountIdWithString(kACCOUNT);
|
||||||
|
auto const account2 = getAccountIdWithString(kACCOUNT2);
|
||||||
|
|
||||||
|
// create a trustline between account and account2 that is frozen (NOT DeepFrozen)
|
||||||
|
auto const trustLineKey = ripple::keylet::line(account, account2, ripple::Currency{kCURRENCY}).key;
|
||||||
|
auto const trustlineFrozen = createRippleStateLedgerObject(
|
||||||
|
"USD", kACCOUNT, 8, kACCOUNT, 1000, kACCOUNT2, 2000, kINDEX1, 2, ripple::lsfLowFreeze
|
||||||
|
);
|
||||||
|
|
||||||
|
ON_CALL(*backend_, doFetchLedgerObject(trustLineKey, kLEDGER_SEQ_OBJECT, _))
|
||||||
|
.WillByDefault(Return(trustlineFrozen.getSerializer().peekData()));
|
||||||
|
|
||||||
|
runSpawn([&](boost::asio::yield_context yield) {
|
||||||
|
EXPECT_FALSE(isDeepFrozen(*backend_, kLEDGER_SEQ_OBJECT, account, ripple::Currency{kCURRENCY}, account2, yield)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, isDeepFrozen_IssuerAndAccountIsSameWillNotBeDeepFrozen)
|
||||||
|
{
|
||||||
|
auto const account = getAccountIdWithString(kACCOUNT);
|
||||||
|
auto const issuer = getAccountIdWithString(kACCOUNT2);
|
||||||
|
|
||||||
|
auto const trustLineKey = ripple::keylet::line(account, issuer, ripple::Currency{kCURRENCY}).key;
|
||||||
|
auto const trustlineDeepFrozen = createRippleStateLedgerObject(
|
||||||
|
"USD", kACCOUNT, 8, kACCOUNT, 1000, kACCOUNT2, 2000, kINDEX1, 2, ripple::lsfLowDeepFreeze
|
||||||
|
);
|
||||||
|
|
||||||
|
ON_CALL(*backend_, doFetchLedgerObject(trustLineKey, kLEDGER_SEQ_OBJECT, _))
|
||||||
|
.WillByDefault(Return(trustlineDeepFrozen.getSerializer().peekData()));
|
||||||
|
|
||||||
|
runSpawn([&](boost::asio::yield_context yield) {
|
||||||
|
// both accounts are same so trustline is not deep frozen
|
||||||
|
EXPECT_FALSE(isDeepFrozen(*backend_, kLEDGER_SEQ_OBJECT, account, ripple::Currency{kCURRENCY}, account, yield));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, isFrozen_IssuerAccountIsGlobalFrozen)
|
||||||
|
{
|
||||||
|
auto const account = getAccountIdWithString(kACCOUNT);
|
||||||
|
auto const issuer = getAccountIdWithString(kACCOUNT2);
|
||||||
|
|
||||||
|
auto const accountObject = createAccountRootObject(kACCOUNT2, ripple::lsfGlobalFreeze, 1, 10, 2, kTXN_ID, 3);
|
||||||
|
auto const issuerKey = ripple::keylet::account(issuer).key;
|
||||||
|
|
||||||
|
ON_CALL(*backend_, doFetchLedgerObject(issuerKey, kLEDGER_SEQ_OBJECT, _))
|
||||||
|
.WillByDefault(Return(accountObject.getSerializer().peekData()));
|
||||||
|
|
||||||
|
runSpawn([&](boost::asio::yield_context yield) {
|
||||||
|
EXPECT_TRUE(isFrozen(*backend_, kLEDGER_SEQ_OBJECT, account, ripple::Currency{kCURRENCY}, issuer, yield));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, isFrozen_IssuerAndAccountIsSameWillNotBeFrozen)
|
||||||
|
{
|
||||||
|
auto const account = getAccountIdWithString(kACCOUNT);
|
||||||
|
auto const issuer = getAccountIdWithString(kACCOUNT2);
|
||||||
|
|
||||||
|
auto const trustLineKey = ripple::keylet::line(account, issuer, ripple::Currency{kCURRENCY}).key;
|
||||||
|
auto const trustlineDeepFrozen = createRippleStateLedgerObject(
|
||||||
|
"USD", kACCOUNT, 8, kACCOUNT, 1000, kACCOUNT2, 2000, kINDEX1, 2, ripple::lsfHighFreeze
|
||||||
|
);
|
||||||
|
|
||||||
|
ON_CALL(*backend_, doFetchLedgerObject(trustLineKey, kLEDGER_SEQ_OBJECT, _))
|
||||||
|
.WillByDefault(Return(trustlineDeepFrozen.getSerializer().peekData()));
|
||||||
|
|
||||||
|
runSpawn([&](boost::asio::yield_context yield) {
|
||||||
|
EXPECT_FALSE(isFrozen(*backend_, kLEDGER_SEQ_OBJECT, account, ripple::Currency{kCURRENCY}, account, yield));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, isFrozen_IssuerTrustLineIsFrozen)
|
||||||
|
{
|
||||||
|
auto const account = getAccountIdWithString(kACCOUNT);
|
||||||
|
auto const issuer = getAccountIdWithString(kACCOUNT2);
|
||||||
|
ripple::Currency const currency{kCURRENCY};
|
||||||
|
|
||||||
|
auto const trustLineKey = ripple::keylet::line(account, issuer, currency).key;
|
||||||
|
|
||||||
|
// issuer is higher than account, so the correct flag to set is High freeze
|
||||||
|
auto const trustlineFrozen = createRippleStateLedgerObject(
|
||||||
|
"USD", kACCOUNT, 8, kACCOUNT, 1000, kACCOUNT2, 2000, kINDEX1, 2, ripple::lsfHighFreeze
|
||||||
|
);
|
||||||
|
|
||||||
|
ON_CALL(*backend_, doFetchLedgerObject(trustLineKey, kLEDGER_SEQ_OBJECT, _))
|
||||||
|
.WillByDefault(Return(trustlineFrozen.getSerializer().peekData()));
|
||||||
|
|
||||||
|
runSpawn([&](boost::asio::yield_context yield) {
|
||||||
|
EXPECT_TRUE(isFrozen(*backend_, kLEDGER_SEQ_OBJECT, account, currency, issuer, yield));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, isFrozen_IssuerWithLowFreezeIsNotFrozen)
|
||||||
|
{
|
||||||
|
auto const account = getAccountIdWithString(kACCOUNT);
|
||||||
|
auto const issuer = getAccountIdWithString(kACCOUNT2);
|
||||||
|
ripple::Currency const currency{kCURRENCY};
|
||||||
|
|
||||||
|
auto const trustLineKey = ripple::keylet::line(account, issuer, currency).key;
|
||||||
|
|
||||||
|
// issuer is higher than account, but the flag set here is low freeze
|
||||||
|
auto const trustlineFrozen = createRippleStateLedgerObject(
|
||||||
|
"USD", kACCOUNT, 8, kACCOUNT, 1000, kACCOUNT2, 2000, kINDEX1, 2, ripple::lsfLowFreeze
|
||||||
|
);
|
||||||
|
|
||||||
|
ON_CALL(*backend_, doFetchLedgerObject(trustLineKey, kLEDGER_SEQ_OBJECT, _))
|
||||||
|
.WillByDefault(Return(trustlineFrozen.getSerializer().peekData()));
|
||||||
|
|
||||||
|
runSpawn([&](boost::asio::yield_context yield) {
|
||||||
|
EXPECT_FALSE(isFrozen(*backend_, kLEDGER_SEQ_OBJECT, account, currency, issuer, yield));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, AccountHolds_TrustLineNotfrozen)
|
||||||
|
{
|
||||||
|
auto const account = getAccountIdWithString(kACCOUNT);
|
||||||
|
auto const issuer = getAccountIdWithString(kACCOUNT2);
|
||||||
|
ripple::Currency const currency{kCURRENCY};
|
||||||
|
|
||||||
|
auto const trustLineKey = ripple::keylet::line(account, issuer, currency).key;
|
||||||
|
auto const trustLine =
|
||||||
|
createRippleStateLedgerObject(kCURRENCY, kACCOUNT2, 500, kACCOUNT, 1000, kACCOUNT2, 1000, kTXN_ID, 1, 0);
|
||||||
|
|
||||||
|
EXPECT_CALL(*backend_, doFetchLedgerObject(trustLineKey, kLEDGER_SEQ_OBJECT, _))
|
||||||
|
.WillOnce(Return(trustLine.getSerializer().peekData()));
|
||||||
|
|
||||||
|
runSpawn([&](boost::asio::yield_context yield) {
|
||||||
|
auto const result = accountHolds(
|
||||||
|
*backend_, *mockAmendmentCenterPtr_, kLEDGER_SEQ_OBJECT, account, currency, issuer, false, yield
|
||||||
|
);
|
||||||
|
// Check issuer has a balance of 500
|
||||||
|
EXPECT_EQ(result, ripple::STAmount(getIssue(kCURRENCY, kACCOUNT2), 500));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, AccountHolds_NoTrustLine)
|
||||||
|
{
|
||||||
|
auto const account = getAccountIdWithString(kACCOUNT);
|
||||||
|
auto const issuer = getAccountIdWithString(kACCOUNT2);
|
||||||
|
ripple::Currency const currency{kCURRENCY};
|
||||||
|
|
||||||
|
auto const key = ripple::keylet::line(account, issuer, currency).key;
|
||||||
|
|
||||||
|
// return no trustline found
|
||||||
|
EXPECT_CALL(*backend_, doFetchLedgerObject(key, kLEDGER_SEQ_OBJECT, _)).WillOnce(Return(std::nullopt));
|
||||||
|
|
||||||
|
runSpawn([&](boost::asio::yield_context yield) {
|
||||||
|
auto const result = accountHolds(
|
||||||
|
*backend_, *mockAmendmentCenterPtr_, kLEDGER_SEQ_OBJECT, account, currency, issuer, false, yield
|
||||||
|
);
|
||||||
|
// balance is 0 as trustline is frozen
|
||||||
|
EXPECT_EQ(result, ripple::STAmount(getIssue(kCURRENCY, kACCOUNT2), 0));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, AccountHolds_TrustLineButFrozen)
|
||||||
|
{
|
||||||
|
auto const account = getAccountIdWithString(kACCOUNT);
|
||||||
|
auto const issuer = getAccountIdWithString(kACCOUNT2);
|
||||||
|
ripple::Currency const currency{kCURRENCY};
|
||||||
|
|
||||||
|
// balance of 500, but trustline is frozen
|
||||||
|
auto const trustLineKey = ripple::keylet::line(account, issuer, currency).key;
|
||||||
|
|
||||||
|
auto const trustLine = createRippleStateLedgerObject(
|
||||||
|
kCURRENCY, kACCOUNT2, 500, kACCOUNT, 1000, kACCOUNT2, 1000, kTXN_ID, 1, ripple::lsfHighFreeze
|
||||||
|
);
|
||||||
|
|
||||||
|
ON_CALL(*backend_, doFetchLedgerObject(trustLineKey, kLEDGER_SEQ_OBJECT, _))
|
||||||
|
.WillByDefault(Return(trustLine.getSerializer().peekData()));
|
||||||
|
|
||||||
|
runSpawn([&](boost::asio::yield_context yield) {
|
||||||
|
auto const result = accountHolds(
|
||||||
|
*backend_, *mockAmendmentCenterPtr_, kLEDGER_SEQ_OBJECT, account, currency, issuer, true, yield
|
||||||
|
);
|
||||||
|
EXPECT_EQ(result, ripple::STAmount(getIssue(kCURRENCY, kACCOUNT2), 0));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(RPCHelpersTest, AccountHoldsFixLPTAmendmentDisabled)
|
TEST_F(RPCHelpersTest, AccountHoldsFixLPTAmendmentDisabled)
|
||||||
{
|
{
|
||||||
auto ammAccount = getAccountIdWithString(kAMM_ACCOUNT);
|
auto ammAccount = getAccountIdWithString(kAMM_ACCOUNT);
|
||||||
|
|||||||
@@ -739,7 +739,8 @@ TEST_F(RPCAccountLinesHandlerTest, OptionalResponseField)
|
|||||||
"no_ripple": false,
|
"no_ripple": false,
|
||||||
"no_ripple_peer": true,
|
"no_ripple_peer": true,
|
||||||
"peer_authorized": true,
|
"peer_authorized": true,
|
||||||
"freeze_peer": true
|
"freeze_peer": true,
|
||||||
|
"deep_freeze_peer": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
"account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
@@ -752,7 +753,8 @@ TEST_F(RPCAccountLinesHandlerTest, OptionalResponseField)
|
|||||||
"no_ripple": true,
|
"no_ripple": true,
|
||||||
"no_ripple_peer": false,
|
"no_ripple_peer": false,
|
||||||
"authorized": true,
|
"authorized": true,
|
||||||
"freeze": true
|
"freeze": true,
|
||||||
|
"deep_freeze": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})";
|
})";
|
||||||
@@ -783,12 +785,14 @@ TEST_F(RPCAccountLinesHandlerTest, OptionalResponseField)
|
|||||||
line1.setFlag(ripple::lsfHighAuth);
|
line1.setFlag(ripple::lsfHighAuth);
|
||||||
line1.setFlag(ripple::lsfHighNoRipple);
|
line1.setFlag(ripple::lsfHighNoRipple);
|
||||||
line1.setFlag(ripple::lsfHighFreeze);
|
line1.setFlag(ripple::lsfHighFreeze);
|
||||||
|
line1.setFlag(ripple::lsfHighDeepFreeze);
|
||||||
bbs.push_back(line1.getSerializer().peekData());
|
bbs.push_back(line1.getSerializer().peekData());
|
||||||
|
|
||||||
auto line2 = createRippleStateLedgerObject("USD", kACCOUNT2, 20, kACCOUNT, 200, kACCOUNT2, 400, kTXN_ID, 0);
|
auto line2 = createRippleStateLedgerObject("USD", kACCOUNT2, 20, kACCOUNT, 200, kACCOUNT2, 400, kTXN_ID, 0);
|
||||||
line2.setFlag(ripple::lsfLowAuth);
|
line2.setFlag(ripple::lsfLowAuth);
|
||||||
line2.setFlag(ripple::lsfLowNoRipple);
|
line2.setFlag(ripple::lsfLowNoRipple);
|
||||||
line2.setFlag(ripple::lsfLowFreeze);
|
line2.setFlag(ripple::lsfLowFreeze);
|
||||||
|
line2.setFlag(ripple::lsfLowDeepFreeze);
|
||||||
bbs.push_back(line2.getSerializer().peekData());
|
bbs.push_back(line2.getSerializer().peekData());
|
||||||
|
|
||||||
ON_CALL(*backend_, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
ON_CALL(*backend_, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||||
|
|||||||
@@ -1156,6 +1156,71 @@ generateNormalPathBookOffersTestBundles()
|
|||||||
},
|
},
|
||||||
.ledgerObjectCalls = 6,
|
.ledgerObjectCalls = 6,
|
||||||
.mockedOffers = std::vector<ripple::STObject>{gets10USDPays20XRPOffer},
|
.mockedOffers = std::vector<ripple::STObject>{gets10USDPays20XRPOffer},
|
||||||
|
.expectedJson = fmt::format(
|
||||||
|
R"({{
|
||||||
|
"ledger_hash":"{}",
|
||||||
|
"ledger_index":300,
|
||||||
|
"offers":
|
||||||
|
[
|
||||||
|
{{
|
||||||
|
"Account":"{}",
|
||||||
|
"BookDirectory":"{}",
|
||||||
|
"BookNode":"0",
|
||||||
|
"Flags":0,
|
||||||
|
"LedgerEntryType":"Offer",
|
||||||
|
"OwnerNode":"0",
|
||||||
|
"PreviousTxnID":"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"PreviousTxnLgrSeq":0,
|
||||||
|
"Sequence":0,
|
||||||
|
"TakerPays":"20",
|
||||||
|
"TakerGets":{{
|
||||||
|
"currency":"USD",
|
||||||
|
"issuer":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"value":"10"
|
||||||
|
}},
|
||||||
|
"index":"E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC321",
|
||||||
|
"owner_funds":"{}",
|
||||||
|
"quality":"{}",
|
||||||
|
"taker_gets_funded":{{
|
||||||
|
"currency":"USD",
|
||||||
|
"issuer":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"value":"0"
|
||||||
|
}},
|
||||||
|
"taker_pays_funded":"0"
|
||||||
|
}}
|
||||||
|
]
|
||||||
|
}})",
|
||||||
|
kLEDGER_HASH,
|
||||||
|
kACCOUNT2,
|
||||||
|
kPAYS20_XRP_GETS10_USD_BOOK_DIR,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
),
|
||||||
|
},
|
||||||
|
BookOffersNormalTestBundle{
|
||||||
|
.testName = "PaysXRPGetsUSDIsDeepFrozen",
|
||||||
|
.inputJson = paysXRPGetsUSDInputJson,
|
||||||
|
// prepare offer dir index
|
||||||
|
.mockedSuccessors =
|
||||||
|
std::map<ripple::uint256, std::optional<ripple::uint256>>{
|
||||||
|
{getsUSDPaysXRPBook, ripple::uint256{kPAYS20_XRP_GETS10_USD_BOOK_DIR}},
|
||||||
|
{ripple::uint256{kPAYS20_XRP_GETS10_USD_BOOK_DIR}, std::optional<ripple::uint256>{}}
|
||||||
|
},
|
||||||
|
.mockedLedgerObjects =
|
||||||
|
std::map<ripple::uint256, ripple::Blob>{
|
||||||
|
// book dir object
|
||||||
|
{ripple::uint256{kPAYS20_XRP_GETS10_USD_BOOK_DIR},
|
||||||
|
createOwnerDirLedgerObject({ripple::uint256{kINDEX2}}, kINDEX1).getSerializer().peekData()},
|
||||||
|
// gets issuer account object, is deep frozen so unfunded
|
||||||
|
{ripple::keylet::account(account).key,
|
||||||
|
createAccountRootObject(
|
||||||
|
kACCOUNT, ripple::lsfLowDeepFreeze, 2, 200, 2, kINDEX1, 2, kTRANSFER_RATE_X2
|
||||||
|
)
|
||||||
|
.getSerializer()
|
||||||
|
.peekData()},
|
||||||
|
},
|
||||||
|
.ledgerObjectCalls = 4,
|
||||||
|
.mockedOffers = std::vector<ripple::STObject>{gets10USDPays20XRPOffer},
|
||||||
.expectedJson = fmt::format(
|
.expectedJson = fmt::format(
|
||||||
R"({{
|
R"({{
|
||||||
"ledger_hash":"{}",
|
"ledger_hash":"{}",
|
||||||
@@ -1197,6 +1262,74 @@ generateNormalPathBookOffersTestBundles()
|
|||||||
2
|
2
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
BookOffersNormalTestBundle{
|
||||||
|
.testName = "PaysXRPGetsUSDTrustLineFrozenAndIsDeepFrozen",
|
||||||
|
.inputJson = paysXRPGetsUSDInputJson,
|
||||||
|
// prepare offer dir index
|
||||||
|
.mockedSuccessors =
|
||||||
|
std::map<ripple::uint256, std::optional<ripple::uint256>>{
|
||||||
|
{getsUSDPaysXRPBook, ripple::uint256{kPAYS20_XRP_GETS10_USD_BOOK_DIR}},
|
||||||
|
{ripple::uint256{kPAYS20_XRP_GETS10_USD_BOOK_DIR}, std::optional<ripple::uint256>{}}
|
||||||
|
},
|
||||||
|
.mockedLedgerObjects =
|
||||||
|
std::map<ripple::uint256, ripple::Blob>{
|
||||||
|
// book dir object
|
||||||
|
{ripple::uint256{kPAYS20_XRP_GETS10_USD_BOOK_DIR},
|
||||||
|
createOwnerDirLedgerObject({ripple::uint256{kINDEX2}}, kINDEX1).getSerializer().peekData()},
|
||||||
|
// gets issuer account object, is deep frozen so unfunded
|
||||||
|
{ripple::keylet::account(account).key,
|
||||||
|
createAccountRootObject(
|
||||||
|
kACCOUNT, ripple::lsfLowDeepFreeze, 2, 200, 2, kINDEX1, 2, kTRANSFER_RATE_X2
|
||||||
|
)
|
||||||
|
.getSerializer()
|
||||||
|
.peekData()},
|
||||||
|
{ripple::keylet::line(account2, account, ripple::to_currency("USD")).key,
|
||||||
|
frozenTrustLine.getSerializer().peekData()},
|
||||||
|
|
||||||
|
},
|
||||||
|
.ledgerObjectCalls = 6,
|
||||||
|
.mockedOffers = std::vector<ripple::STObject>{gets10USDPays20XRPOffer},
|
||||||
|
.expectedJson = fmt::format(
|
||||||
|
R"({{
|
||||||
|
"ledger_hash":"{}",
|
||||||
|
"ledger_index":300,
|
||||||
|
"offers":
|
||||||
|
[
|
||||||
|
{{
|
||||||
|
"Account":"{}",
|
||||||
|
"BookDirectory":"{}",
|
||||||
|
"BookNode":"0",
|
||||||
|
"Flags":0,
|
||||||
|
"LedgerEntryType":"Offer",
|
||||||
|
"OwnerNode":"0",
|
||||||
|
"PreviousTxnID":"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"PreviousTxnLgrSeq":0,
|
||||||
|
"Sequence":0,
|
||||||
|
"TakerPays":"20",
|
||||||
|
"TakerGets":{{
|
||||||
|
"currency":"USD",
|
||||||
|
"issuer":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"value":"10"
|
||||||
|
}},
|
||||||
|
"index":"E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC321",
|
||||||
|
"owner_funds":"{}",
|
||||||
|
"quality":"{}",
|
||||||
|
"taker_gets_funded":{{
|
||||||
|
"currency":"USD",
|
||||||
|
"issuer":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"value":"0"
|
||||||
|
}},
|
||||||
|
"taker_pays_funded":"0"
|
||||||
|
}}
|
||||||
|
]
|
||||||
|
}})",
|
||||||
|
kLEDGER_HASH,
|
||||||
|
kACCOUNT2,
|
||||||
|
kPAYS20_XRP_GETS10_USD_BOOK_DIR,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user