Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add deep freeze feature (XLS-77d) #5187

Merged
merged 54 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
e57d068
Implement Deep Freeze
HowardHinnant Aug 2, 2024
a0d48ae
[FOLD] Move feature to top of list
HowardHinnant Oct 31, 2024
4aac190
[FOLD] Make use of the deep freeze flags malformed prior
HowardHinnant Oct 31, 2024
306a112
Fixed creation of buy offer transaction to fail with tecFROZEN instantly
vvysokikh1 Nov 15, 2024
f5efa31
Fixed comments #1
vvysokikh1 Nov 18, 2024
8e1977f
Reworked freeze flag handling in SetTrust
vvysokikh1 Nov 20, 2024
a162663
Moved modified trustline flags extraction into separate function
vvysokikh1 Nov 20, 2024
c7c26ac
Added more check to test cases
vvysokikh1 Nov 21, 2024
805102a
Added payment tests for freeze and deep freeze
vvysokikh1 Nov 22, 2024
de58a26
Clarified behavior of individual freeze
vvysokikh1 Nov 22, 2024
91d291a
Added offer test for freeze and deep freeze
vvysokikh1 Nov 28, 2024
e0d59ef
More offer tests
vvysokikh1 Dec 2, 2024
ffa6ccd
Fixed typo
vvysokikh1 Dec 4, 2024
f9107a7
Fixed tx flags check in case trustline doesn't exist yet
vvysokikh1 Dec 4, 2024
1f9ecb8
Added tests for trustline creation freeze handling
vvysokikh1 Dec 4, 2024
010f36d
Partially fixed comments
vvysokikh1 Dec 6, 2024
6bae95d
Partially fixed comments
vvysokikh1 Dec 10, 2024
b5a10ec
Fixed buy offer crossing when deep frozen
vvysokikh1 Dec 10, 2024
a1d7dac
Reverted deep freeze check tests
vvysokikh1 Jan 6, 2025
c971db5
Added revamped deep freeze check tests
vvysokikh1 Jan 10, 2025
9f17d9f
Reverted deep freeze AMM tests
vvysokikh1 Jan 13, 2025
d75894a
Added some AMM tests and fixed comments
vvysokikh1 Jan 15, 2025
03f7b5d
Added offer tests with trustline frozen by currency holder
vvysokikh1 Jan 15, 2025
ae5fae2
Added longer path payment tests
vvysokikh1 Jan 17, 2025
c60d491
Added NFT deep freeze tests
vvysokikh1 Jan 17, 2025
0d8855a
Fixed flag
vvysokikh1 Jan 17, 2025
70235b6
Merge branch 'develop' of github.com:vvysokikh1/rippled into deep_freeze
vvysokikh1 Jan 17, 2025
a73ea01
Small fixes
vvysokikh1 Jan 17, 2025
411a0f0
Unity build fix
vvysokikh1 Jan 17, 2025
4c5c9cc
simplified unity build fix
vvysokikh1 Jan 17, 2025
9f21f5d
Fixed tests
vvysokikh1 Jan 17, 2025
8c40ab9
Fixed NFT deep freeze offer acceptance
vvysokikh1 Jan 20, 2025
c5aa145
Added invariant check for deep freeze flag on a trust line
vvysokikh1 Jan 20, 2025
851e619
Added deep freeze into acoount_lines rpc response
vvysokikh1 Jan 20, 2025
290b908
Uncommented NFT test with freeze on currency holder side
vvysokikh1 Jan 20, 2025
9db6765
Added more invariant tests
vvysokikh1 Jan 21, 2025
7ba80fe
Comment fixes
vvysokikh1 Jan 22, 2025
79a4da3
Comment fixes
vvysokikh1 Jan 23, 2025
c1778e5
Added invariant check for frozen trust line balance change
vvysokikh1 Jan 23, 2025
edf659e
Initial invariant trustline balance checks tests
vvysokikh1 Jan 27, 2025
d7360c9
reverted commented invariant tests
vvysokikh1 Jan 27, 2025
536fff2
removed comments about frozen offer tests
vvysokikh1 Jan 27, 2025
f33eba9
fixed comments
vvysokikh1 Jan 27, 2025
7fcd042
fixed test name
vvysokikh1 Jan 27, 2025
5d032e4
fixed accidential removal of check
vvysokikh1 Jan 28, 2025
0436866
Merge branch 'develop' into deep_freeze
vvysokikh1 Jan 28, 2025
fe9346f
fixed comments
vvysokikh1 Jan 29, 2025
69e24bc
fixed build
vvysokikh1 Jan 29, 2025
9aa72eb
comment fix
vvysokikh1 Jan 29, 2025
4d58b4f
switched to Issue type instead of std::pair
vvysokikh1 Jan 29, 2025
f4c3e1b
comment fix
vvysokikh1 Jan 29, 2025
a891d62
Merge branch 'develop' into deep_freeze
vvysokikh1 Jan 30, 2025
bd0e5cc
Merge branch 'develop' into deep_freeze
ximinez Jan 31, 2025
024c16c
Add deep freeze feature (XLS-77d)
vvysokikh1 Jan 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/xrpl/protocol/Feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ namespace detail {
// Feature.cpp. Because it's only used to reserve storage, and determine how
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
// the actual number of amendments. A LogicError on startup will verify this.
static constexpr std::size_t numFeatures = 80;
static constexpr std::size_t numFeatures = 81;

/** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated
Expand Down
2 changes: 2 additions & 0 deletions include/xrpl/protocol/LedgerFormats.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ enum LedgerSpecificFlags {
lsfHighFreeze = 0x00800000, // True, high side has set freeze flag
lsfAMMNode = 0x01000000, // True, trust line to AMM. Used by client
// apps to identify payments via AMM.
lsfLowDeepFreeze = 0x02000000,
lsfHighDeepFreeze = 0x04000000,

// ltSIGNER_LIST
lsfOneOwnerCount = 0x00010000, // True, uses only one OwnerCount
Expand Down
4 changes: 3 additions & 1 deletion include/xrpl/protocol/TxFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,11 @@ constexpr std::uint32_t tfSetNoRipple = 0x00020000;
constexpr std::uint32_t tfClearNoRipple = 0x00040000;
constexpr std::uint32_t tfSetFreeze = 0x00100000;
constexpr std::uint32_t tfClearFreeze = 0x00200000;
constexpr std::uint32_t tfSetDeepFreeze = 0x00400000;
constexpr std::uint32_t tfClearDeepFreeze = 0x00800000;
constexpr std::uint32_t tfTrustSetMask =
~(tfUniversal | tfSetfAuth | tfSetNoRipple | tfClearNoRipple | tfSetFreeze |
tfClearFreeze);
tfClearFreeze | tfSetDeepFreeze | tfClearDeepFreeze);

// EnableAmendment flags:
constexpr std::uint32_t tfGotMajority = 0x00010000;
Expand Down
1 change: 1 addition & 0 deletions include/xrpl/protocol/detail/features.macro
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

// InvariantsV1_1 will be changes to Supported::yes when all the
// invariants expected to be included under it are complete.
XRPL_FEATURE(DeepFreeze, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(MPTokensV1, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(InvariantsV1_1, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (NFTokenPageLinks, Supported::yes, VoteBehavior::DefaultNo)
Expand Down
184 changes: 184 additions & 0 deletions src/test/app/AMMExtended_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3615,6 +3615,184 @@ struct AMMExtended_test : public jtx::AMMTest
}
}

void
testRippleDeepState(FeatureBitset features)
{
testcase("RippleState Deep Freeze");

using namespace test::jtx;
Env env(*this, features);

Account const G1{"G1"};
Account const alice{"alice"};
Account const bob{"bob"};

env.fund(XRP(1'000), G1, alice, bob);
env.close();

env.trust(G1["USD"](100), bob);
env.trust(G1["USD"](205), alice);
env.close();

env(pay(G1, bob, G1["USD"](10)));
env(pay(G1, alice, G1["USD"](205)));
env.close();

AMM ammAlice(env, alice, XRP(500), G1["USD"](105));

{
auto lines = getAccountLines(env, bob);
if (!BEAST_EXPECT(checkArraySize(lines[jss::lines], 1u)))
return;
BEAST_EXPECT(lines[jss::lines][0u][jss::account] == G1.human());
BEAST_EXPECT(lines[jss::lines][0u][jss::limit] == "100");
BEAST_EXPECT(lines[jss::lines][0u][jss::balance] == "10");
}

{
auto lines = getAccountLines(env, alice, G1["USD"]);
if (!BEAST_EXPECT(checkArraySize(lines[jss::lines], 1u)))
return;
BEAST_EXPECT(lines[jss::lines][0u][jss::account] == G1.human());
BEAST_EXPECT(lines[jss::lines][0u][jss::limit] == "205");
// 105 transferred to AMM
BEAST_EXPECT(lines[jss::lines][0u][jss::balance] == "100");
}

{
// Account with line unfrozen (proving operations normally work)
// test: can make Payment on that line
env(pay(alice, bob, G1["USD"](1)));

// test: can receive Payment on that line
env(pay(bob, alice, G1["USD"](1)));
env.close();
}

{
// Is created via a TrustSet with SetFreeze flag
// test: sets LowFreeze | HighFreeze flags
env(trust(G1, bob["USD"](0), tfSetFreeze | tfSetDeepFreeze));
auto affected = env.meta()->getJson(
JsonOptions::none)[sfAffectedNodes.fieldName];
if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
return;
auto ff =
affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
BEAST_EXPECT(
ff[sfLowLimit.fieldName] ==
G1["USD"](0).value().getJson(JsonOptions::none));
if (features[featureDeepFreeze])
{
BEAST_EXPECT(ff[jss::Flags].asUInt() & lsfLowDeepFreeze);
BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighDeepFreeze));
}
else
{
BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfLowDeepFreeze));
BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighDeepFreeze));
}
env.close();
}

{
// Account with line deep frozen by issuer
// test: can not buy more assets on that line
if (features[featureDeepFreeze])
{
env(offer(bob, G1["USD"](5), XRP(25)), ter(tecFROZEN));
}
else
{
env(offer(bob, G1["USD"](5), XRP(25)));
}
env.close();
}

{
// test: can not sell assets from that line
env(offer(bob, XRP(1), G1["USD"](5)), ter(tecUNFUNDED_OFFER));

// test: can not make Payment from that line
env(pay(bob, alice, G1["USD"](1)), ter(tecPATH_DRY));

if (features[featureDeepFreeze])
{
// test: can not receive Payment on that line
env(pay(alice, bob, G1["USD"](1)), ter(tecPATH_DRY));
}
else
{
// test: can receive Payment on that line
env(pay(alice, bob, G1["USD"](1)));
}
}

{
// check G1 account lines
// test: shows deep freeze
auto lines = getAccountLines(env, G1);
Json::Value bobLine;
for (auto const& it : lines[jss::lines])
{
if (it[jss::account] == bob.human())
{
bobLine = it;
break;
}
}
if (!BEAST_EXPECT(bobLine))
return;
BEAST_EXPECT(bobLine[jss::freeze] == true);
if (features[featureDeepFreeze])
BEAST_EXPECT(bobLine[jss::balance] == "-10");
else
BEAST_EXPECT(bobLine[jss::balance] == "-16");
}

{
// test: shows deep freeze peer
auto lines = getAccountLines(env, bob);
Json::Value g1Line;
for (auto const& it : lines[jss::lines])
{
if (it[jss::account] == G1.human())
{
g1Line = it;
break;
}
}
if (!BEAST_EXPECT(g1Line))
return;
BEAST_EXPECT(g1Line[jss::freeze_peer] == true);
if (features[featureDeepFreeze])
BEAST_EXPECT(g1Line[jss::balance] == "10");
else
BEAST_EXPECT(g1Line[jss::balance] == "16");
}

{
// Is cleared via a TrustSet with ClearDeepFreeze flag
// test: sets LowDeepFreeze | HighDeepFreeze flags
env(trust(G1, bob["USD"](0), tfClearDeepFreeze));
auto affected = env.meta()->getJson(
JsonOptions::none)[sfAffectedNodes.fieldName];
if (!features[featureDeepFreeze] &&
BEAST_EXPECT(checkArraySize(affected, 1u)))
return;
if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
return;
auto ff =
affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
BEAST_EXPECT(
ff[sfLowLimit.fieldName] ==
G1["USD"](0).value().getJson(JsonOptions::none));
BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfLowDeepFreeze));
BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighDeepFreeze));
env.close();
}
}

void
testGlobalFreeze(FeatureBitset features)
{
Expand Down Expand Up @@ -4129,7 +4307,13 @@ struct AMMExtended_test : public jtx::AMMTest
{
using namespace test::jtx;
auto const sa = supported_amendments();
testRippleState(sa - featureDeepFreeze);
testRippleDeepState(sa - featureDeepFreeze);
testGlobalFreeze(sa - featureDeepFreeze);
testOffersWhenFrozen(sa - featureDeepFreeze);

testRippleState(sa);
testRippleDeepState(sa);
testGlobalFreeze(sa);
testOffersWhenFrozen(sa);
}
Expand Down
43 changes: 43 additions & 0 deletions src/test/app/AMM_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4397,6 +4397,48 @@ struct AMM_test : public jtx::AMMTest
0,
std::nullopt,
{features});

// Individually deep frozen account
if (features[featureDeepFreeze])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need to repeat the code. Just add a conditional error:

auto const err = features[featureDeepFreeze] ? ter(tecPATH_DRY) : ter(tesSUCCESS)

And then use it in pay:

env(pay(alice, carol, USD(1)),
            path(~USD),
            sendmax(XRP(10)),
            txflags(tfNoRippleDirect | tfPartialPayment),
            err);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, you shouldn't test here and other updated unit-tests if the feature is disabled because trust is going to fail. You need a separate test for disabled feature in SetTrust and also add to SetTrust tests for invalid combination of the flags. Also need to add OfferCreate and offer crossing, if not added yet, to Offer.

{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AMM Create, Deposit, Withdraw are not impacted in any way by deep freeze, correct? Just want to check.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from design perspective it should not, deep freeze imposes a superset of restrictions of the existing regular freeze feature. so any restrictions in these transactions should have already been implemented through the freeze feature already.

testAMM(
[&](AMM& ammAlice, Env& env) {
env(trust(
gw, carol["USD"](0), tfSetFreeze | tfSetDeepFreeze));
env(trust(
gw, alice["USD"](0), tfSetFreeze | tfSetDeepFreeze));
env.close();
env(pay(alice, carol, USD(1)),
path(~USD),
sendmax(XRP(10)),
txflags(tfNoRippleDirect | tfPartialPayment),
ter(tecPATH_DRY));
},
std::nullopt,
0,
std::nullopt,
{features});
}
else
{
testAMM(
[&](AMM& ammAlice, Env& env) {
env(trust(
gw, carol["USD"](0), tfSetFreeze | tfSetDeepFreeze));
env(trust(
gw, alice["USD"](0), tfSetFreeze | tfSetDeepFreeze));
env.close();
env(pay(alice, carol, USD(1)),
path(~USD),
sendmax(XRP(10)),
txflags(tfNoRippleDirect | tfPartialPayment),
ter(tesSUCCESS));
},
std::nullopt,
0,
std::nullopt,
{features});
}
}

void
Expand Down Expand Up @@ -6882,6 +6924,7 @@ struct AMM_test : public jtx::AMMTest
testBasicPaymentEngine(all - fixAMMv1_1);
testBasicPaymentEngine(all - fixReducedOffersV2);
testBasicPaymentEngine(all - fixAMMv1_1 - fixReducedOffersV2);
testBasicPaymentEngine(all - featureDeepFreeze);
testAMMTokens();
testAmendment();
testFlags();
Expand Down
67 changes: 67 additions & 0 deletions src/test/app/Check_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,72 @@ class Check_test : public beast::unit_test::suite
env(trust(alice, USD(0), tfClearFreeze));
env.close();
}
{
// Deep Frozen trust line. Check creation should be similar to
// payment behavior in the face of frozen trust lines.
env.trust(USD(1000), alice);
env.trust(USD(1000), bob);
env.close();
env(pay(gw1, alice, USD(25)));
env(pay(gw1, bob, USD(25)));
env.close();

// Setting trustline deep freeze in one direction prevents alice
// from creating a check for USD. And bob and gw1 should not be
// able to create a check for USD to alice.
env(trust(gw1, alice["USD"](0), tfSetFreeze | tfSetDeepFreeze));
env.close();
env(check::create(alice, bob, USD(50)), ter(tecFROZEN));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should add deep freeze check to CreateCheck transactor.

env.close();
env(pay(alice, bob, USD(1)), ter(tecPATH_DRY));
env.close();
env(check::create(bob, alice, USD(50)));
env.close();
if (features[featureDeepFreeze])
env(pay(bob, alice, USD(1)), ter(tecPATH_DRY));
else
env(pay(bob, alice, USD(1)));
env.close();
env(check::create(gw1, alice, USD(50)));
env.close();
env(pay(gw1, alice, USD(1)));
env.close();

// Clear that freeze. Now check creation works.
env(trust(gw1, alice["USD"](0), tfClearFreeze | tfClearDeepFreeze));
env.close();
env(check::create(alice, bob, USD(50)));
env.close();
env(check::create(bob, alice, USD(50)));
env.close();
env(check::create(gw1, alice, USD(50)));
env.close();

// Deep Freezing in the other direction does effect alice's USD
// check creation, and prevents bob and gw1 from writing a check
// for USD to alice.
env(trust(alice, USD(0), tfSetFreeze | tfSetDeepFreeze));
env.close();
env(check::create(alice, bob, USD(50)));
env.close();
if (features[featureDeepFreeze])
env(pay(alice, bob, USD(1)), ter(tecPATH_DRY));
else
env(pay(alice, bob, USD(1)));
env.close();
env(check::create(bob, alice, USD(50)), ter(tecFROZEN));
env.close();
env(pay(bob, alice, USD(1)), ter(tecPATH_DRY));
env.close();
env(check::create(gw1, alice, USD(50)), ter(tecFROZEN));
env.close();
env(pay(gw1, alice, USD(1)), ter(tecPATH_DRY));
env.close();

// Clear that deep freeze.
env(trust(alice, USD(0), tfClearFreeze | tfClearDeepFreeze));
env.close();
}

// Expired expiration.
env(check::create(alice, bob, USD(50)),
Expand Down Expand Up @@ -2719,6 +2785,7 @@ class Check_test : public beast::unit_test::suite
auto const sa = supported_amendments();
testWithFeats(sa - featureCheckCashMakesTrustLine);
testWithFeats(sa - disallowIncoming);
testWithFeats(sa - featureDeepFreeze);
testWithFeats(sa);

testTrustLineCreation(sa); // Test with featureCheckCashMakesTrustLine
Expand Down
Loading