Skip to content

Commit

Permalink
Implement Deep Freeze
Browse files Browse the repository at this point in the history
  • Loading branch information
HowardHinnant committed Oct 10, 2024
1 parent bf4a7b6 commit b7bb2fa
Show file tree
Hide file tree
Showing 11 changed files with 450 additions and 18 deletions.
3 changes: 2 additions & 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 = 79;
static constexpr std::size_t numFeatures = 80;

/** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated
Expand Down Expand Up @@ -372,6 +372,7 @@ extern uint256 const fixEnforceNFTokenTrustline;
extern uint256 const fixInnerObjTemplate2;
extern uint256 const featureInvariantsV1_1;
extern uint256 const fixNFTokenPageLinks;
extern uint256 const featureDeepFreeze;

} // namespace ripple

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 @@ -298,6 +298,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 @@ -111,9 +111,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 src/libxrpl/protocol/Feature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ REGISTER_FIX (fixNFTokenPageLinks, Supported::yes, VoteBehavior::De
// InvariantsV1_1 will be changes to Supported::yes when all the
// invariants expected to be included under it are complete.
REGISTER_FEATURE(InvariantsV1_1, Supported::no, VoteBehavior::DefaultNo);
REGISTER_FEATURE(DeepFreeze, Supported::yes, VoteBehavior::DefaultNo);

// The following amendments are obsolete, but must remain supported
// because they could potentially get enabled.
Expand Down
208 changes: 208 additions & 0 deletions src/test/app/AMMExtended_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3615,6 +3615,208 @@ 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
env(offer(bob, G1["USD"](5), XRP(25)));
auto affected = env.meta()->getJson(
JsonOptions::none)[sfAffectedNodes.fieldName];
if (!BEAST_EXPECT(checkArraySize(affected, 4u)))
return;
auto ff =
affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
auto amt = STAmount{Issue{to_currency("USD"), noAccount()}, -15}
.value()
.getJson(JsonOptions::none);
if (features[featureDeepFreeze])
{
BEAST_EXPECT(ff[sfHighLimit.fieldName] == Json::nullValue);
BEAST_EXPECT(ff[sfBalance.fieldName] == Json::nullValue);
}
else
{
BEAST_EXPECT(
ff[sfHighLimit.fieldName] ==
bob["USD"](100).value().getJson(JsonOptions::none));
BEAST_EXPECT(ff[sfBalance.fieldName] == amt);
}
env.close();
if (features[featureDeepFreeze])
{
BEAST_EXPECT(ammAlice.expectBalances(
XRP(500), G1["USD"](105), ammAlice.tokens()));
}
else
{
BEAST_EXPECT(ammAlice.expectBalances(
XRP(525), G1["USD"](100), ammAlice.tokens()));
}
}

{
// 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 +4331,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])
{
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
Loading

0 comments on commit b7bb2fa

Please sign in to comment.