feat: Add support for deep freeze (#1875)

fixes #1826
This commit is contained in:
Peter Chen
2025-03-05 11:04:44 -05:00
committed by GitHub
parent 5d2694d36c
commit 8a08c5e6ce
7 changed files with 527 additions and 26 deletions

View File

@@ -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 {

View File

@@ -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
* *

View File

@@ -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);
} }

View File

@@ -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;
}; };
/** /**

View File

@@ -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);

View File

@@ -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));

View File

@@ -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
)
}
}; };
} }