mirror of
https://github.com/XRPLF/rippled.git
synced 2026-02-12 18:02:32 +00:00
Compare commits
10 Commits
bthomee/no
...
tapanito/v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2198146a8 | ||
|
|
c808c46049 | ||
|
|
167147281c | ||
|
|
11e8d1f8a2 | ||
|
|
ba60306610 | ||
|
|
6674500896 | ||
|
|
c5d7ebe93d | ||
|
|
d0b5ca9dab | ||
|
|
5e51893e9b | ||
|
|
3422c11d02 |
@@ -466,11 +466,6 @@ function (add_code_coverage_to_target name scope)
|
||||
target_compile_options(${name} ${scope} $<$<COMPILE_LANGUAGE:CXX>:${COVERAGE_CXX_COMPILER_FLAGS}>
|
||||
$<$<COMPILE_LANGUAGE:C>:${COVERAGE_C_COMPILER_FLAGS}>)
|
||||
|
||||
target_link_libraries(
|
||||
${name}
|
||||
${scope}
|
||||
$<$<LINK_LANGUAGE:CXX>:${COVERAGE_CXX_LINKER_FLAGS}
|
||||
gcov>
|
||||
$<$<LINK_LANGUAGE:C>:${COVERAGE_C_LINKER_FLAGS}
|
||||
gcov>)
|
||||
target_link_libraries(${name} ${scope} $<$<LINK_LANGUAGE:CXX>:${COVERAGE_CXX_LINKER_FLAGS}>
|
||||
$<$<LINK_LANGUAGE:C>:${COVERAGE_C_LINKER_FLAGS}>)
|
||||
endfunction () # add_code_coverage_to_target
|
||||
|
||||
@@ -185,6 +185,7 @@ enum LedgerSpecificFlags {
|
||||
|
||||
// ltVAULT
|
||||
lsfVaultPrivate = 0x00010000,
|
||||
lsfVaultDepositBlocked = 0x00020000, // True, vault deposit is blocked
|
||||
|
||||
// ltLOAN
|
||||
lsfLoanDefault = 0x00010000,
|
||||
|
||||
@@ -270,11 +270,13 @@ constexpr std::uint32_t const tfBatchMask =
|
||||
// LoanPay: True, indicates any excess in this payment can be used
|
||||
// as an overpayment. False, no overpayments will be taken.
|
||||
constexpr std::uint32_t const tfLoanOverpayment = 0x00010000;
|
||||
|
||||
// LoanPay exclusive flags:
|
||||
// tfLoanFullPayment: True, indicates that the payment is an early
|
||||
// full payment. It must pay the entire loan including close
|
||||
// interest and fees, or it will fail. False: Not a full payment.
|
||||
constexpr std::uint32_t const tfLoanFullPayment = 0x00020000;
|
||||
|
||||
// tfLoanLatePayment: True, indicates that the payment is late,
|
||||
// and includes late interest and fees. If the loan is not late,
|
||||
// it will fail. False: not a late payment. If the current payment
|
||||
@@ -291,6 +293,11 @@ constexpr std::uint32_t const tfLoanImpair = 0x00020000;
|
||||
constexpr std::uint32_t const tfLoanUnimpair = 0x00040000;
|
||||
constexpr std::uint32_t const tfLoanManageMask = ~(tfUniversal | tfLoanDefault | tfLoanImpair | tfLoanUnimpair);
|
||||
|
||||
// VaultSet flags:
|
||||
constexpr std::uint32_t const tfVaultDepositBlock = 0x00010000;
|
||||
constexpr std::uint32_t const tfVaultDepositUnblock = 0x00020000;
|
||||
constexpr std::uint32_t const tfVaultSetMask = ~(tfUniversal | tfVaultDepositBlock | tfVaultDepositUnblock);
|
||||
|
||||
// clang-format on
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
// Add new amendments to the top of this list.
|
||||
// Keep it sorted in reverse chronological order.
|
||||
|
||||
XRPL_FIX (LendingProtocolV1_1, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (PermissionedDomainInvariant, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (ExpiredNFTokenOfferRemoval, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (BatchInnerSigs, Supported::yes, VoteBehavior::DefaultNo)
|
||||
|
||||
@@ -1701,10 +1701,21 @@ class LoanBroker_test : public beast::unit_test::suite
|
||||
testRIPD4274MPT();
|
||||
}
|
||||
|
||||
void
|
||||
testFixAmendmentEnabled()
|
||||
{
|
||||
using namespace jtx;
|
||||
testcase("testFixAmendmentEnabled");
|
||||
Env env{*this};
|
||||
|
||||
BEAST_EXPECT(env.enabled(fixLendingProtocolV1_1));
|
||||
}
|
||||
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testFixAmendmentEnabled();
|
||||
testLoanBrokerSetDebtMaximum();
|
||||
testLoanBrokerCoverDepositNullVault();
|
||||
|
||||
|
||||
@@ -4990,6 +4990,97 @@ class Vault_test : public beast::unit_test::suite
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testVaultSetVaultDepositFlagValidation()
|
||||
{
|
||||
using namespace test::jtx;
|
||||
|
||||
auto const all = testable_amendments();
|
||||
|
||||
{
|
||||
testcase("VaultSet VaultDepositBlock fixLendingProtocolV1_1 disabled");
|
||||
Env env{*this, all - fixLendingProtocolV1_1};
|
||||
|
||||
Account owner{"owner"};
|
||||
env.fund(XRP(1'000'000), owner);
|
||||
env.close();
|
||||
|
||||
PrettyAsset asset = xrpIssue();
|
||||
Vault vault{env};
|
||||
|
||||
auto const [tx, keylet] = vault.create({.owner = owner, .asset = asset, .flags = tfVaultPrivate});
|
||||
env(tx, ter(tesSUCCESS), THISLINE);
|
||||
env.close();
|
||||
|
||||
env(vault.set({.owner = owner, .id = keylet.key, .flags = tfVaultDepositBlock}),
|
||||
ter(temDISABLED),
|
||||
THISLINE);
|
||||
env.close();
|
||||
}
|
||||
|
||||
{
|
||||
std::string const prefix = "VaultSet(VaultDepositBlock): ";
|
||||
Env env{*this, all | fixLendingProtocolV1_1};
|
||||
|
||||
Account owner{"owner"};
|
||||
env.fund(XRP(1'000'000), owner);
|
||||
env.close();
|
||||
|
||||
PrettyAsset asset = xrpIssue();
|
||||
Vault vault{env};
|
||||
|
||||
auto const [tx, keylet] = vault.create({.owner = owner, .asset = asset, .flags = tfVaultPrivate});
|
||||
env(tx, ter(tesSUCCESS), THISLINE);
|
||||
env.close();
|
||||
|
||||
{
|
||||
testcase(prefix + "invalid flags");
|
||||
env(vault.set({.owner = owner, .id = keylet.key, .flags = tfVaultDepositBlock | tfVaultDepositUnblock}),
|
||||
ter(temMALFORMED),
|
||||
THISLINE);
|
||||
env.close();
|
||||
}
|
||||
|
||||
{
|
||||
testcase(prefix + "unblock already unblocked vault");
|
||||
// Cannot unblock an already unblocked vault
|
||||
env(vault.set({.owner = owner, .id = keylet.key, .flags = tfVaultDepositUnblock}),
|
||||
ter(tecNO_PERMISSION),
|
||||
THISLINE);
|
||||
}
|
||||
|
||||
{
|
||||
testcase(prefix + "set and clear vault flag");
|
||||
env(vault.set({.owner = owner, .id = keylet.key, .flags = tfVaultDepositBlock}),
|
||||
ter(tesSUCCESS),
|
||||
THISLINE);
|
||||
|
||||
auto sleVault = env.le(keylet);
|
||||
if (!BEAST_EXPECT(sleVault))
|
||||
return;
|
||||
|
||||
if (!BEAST_EXPECT(sleVault->isFlag(lsfVaultDepositBlocked)))
|
||||
return;
|
||||
|
||||
// Cannot block an already blocked vault
|
||||
env(vault.set({.owner = owner, .id = keylet.key, .flags = tfVaultDepositBlock}),
|
||||
ter(tecNO_PERMISSION),
|
||||
THISLINE);
|
||||
|
||||
// Cannot unblock an already unblocked vault
|
||||
env(vault.set({.owner = owner, .id = keylet.key, .flags = tfVaultDepositUnblock}),
|
||||
ter(tesSUCCESS),
|
||||
THISLINE);
|
||||
|
||||
sleVault = env.le(keylet);
|
||||
if (!BEAST_EXPECT(sleVault))
|
||||
return;
|
||||
|
||||
BEAST_EXPECT(!sleVault->isFlag(lsfVaultDepositBlocked));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
@@ -5011,6 +5102,7 @@ public:
|
||||
testVaultClawbackBurnShares();
|
||||
testVaultClawbackAssets();
|
||||
testAssetsMaximum();
|
||||
testVaultSetVaultDepositFlagValidation();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ Vault::set(SetArgs const& args)
|
||||
jv[jss::TransactionType] = jss::VaultSet;
|
||||
jv[jss::Account] = args.owner.human();
|
||||
jv[sfVaultID] = to_string(args.id);
|
||||
if (args.flags)
|
||||
jv[jss::Flags] = *args.flags;
|
||||
return jv;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ struct Vault
|
||||
{
|
||||
Account owner;
|
||||
uint256 id;
|
||||
std::optional<std::uint32_t> flags{};
|
||||
};
|
||||
|
||||
Json::Value
|
||||
|
||||
@@ -21,9 +21,34 @@ VaultSet::checkExtraFeatures(PreflightContext const& ctx)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
VaultSet::getFlagsMask(PreflightContext const& ctx)
|
||||
{
|
||||
return tfVaultSetMask;
|
||||
}
|
||||
|
||||
static bool
|
||||
isValidVaultUpdate(PreflightContext const& ctx)
|
||||
{
|
||||
auto const checkFlags = ctx.rules.enabled(fixLendingProtocolV1_1);
|
||||
|
||||
auto const atLeastOneFieldPresent =
|
||||
ctx.tx.isFieldPresent(sfDomainID) || ctx.tx.isFieldPresent(sfAssetsMaximum) || ctx.tx.isFieldPresent(sfData);
|
||||
|
||||
return atLeastOneFieldPresent ||
|
||||
(checkFlags && (ctx.tx.isFlag(tfVaultDepositBlock) || ctx.tx.isFlag(tfVaultDepositUnblock)));
|
||||
}
|
||||
|
||||
NotTEC
|
||||
VaultSet::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
if ((ctx.tx.isFlag(tfVaultDepositBlock) || ctx.tx.isFlag(tfVaultDepositUnblock)) &&
|
||||
!ctx.rules.enabled(fixLendingProtocolV1_1))
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "VaultSet: flags not supported without fixLendingProtocolV1_1.";
|
||||
return temDISABLED;
|
||||
}
|
||||
|
||||
if (ctx.tx[sfVaultID] == beast::zero)
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "VaultSet: zero/empty vault ID.";
|
||||
@@ -48,12 +73,18 @@ VaultSet::preflight(PreflightContext const& ctx)
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx.tx.isFieldPresent(sfDomainID) && !ctx.tx.isFieldPresent(sfAssetsMaximum) && !ctx.tx.isFieldPresent(sfData))
|
||||
if (!isValidVaultUpdate(ctx))
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "VaultSet: nothing is being updated.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
if (ctx.tx.isFlag(tfVaultDepositBlock) && ctx.tx.isFlag(tfVaultDepositUnblock))
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "VaultSet: cannot set tfVaultDepositBlock and tfVaultDepositUnblock simultaneously.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -107,6 +138,21 @@ VaultSet::preclaim(PreclaimContext const& ctx)
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.view.rules().enabled(fixLendingProtocolV1_1))
|
||||
{
|
||||
if (vault->isFlag(lsfVaultDepositBlocked) && ctx.tx.isFlag(tfVaultDepositBlock))
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "VaultSet: vault deposit is already blocked";
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
|
||||
if (!vault->isFlag(lsfVaultDepositBlocked) && ctx.tx.isFlag(tfVaultDepositUnblock))
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "VaultSet: vault deposit is already unblocked";
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -164,6 +210,15 @@ VaultSet::doApply()
|
||||
view().update(sleIssuance);
|
||||
}
|
||||
|
||||
if (view().rules().enabled(fixLendingProtocolV1_1))
|
||||
{
|
||||
if (tx.isFlag(tfVaultDepositBlock))
|
||||
vault->setFlag(lsfVaultDepositBlocked);
|
||||
|
||||
if (tx.isFlag(tfVaultDepositUnblock))
|
||||
vault->clearFlag(lsfVaultDepositBlocked);
|
||||
}
|
||||
|
||||
// Note, we must update Vault object even if only DomainID is being updated
|
||||
// in Issuance object. Otherwise it's really difficult for Vault invariants
|
||||
// to verify the operation.
|
||||
|
||||
@@ -13,6 +13,9 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static bool
|
||||
checkExtraFeatures(PreflightContext const& ctx);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user