mirror of
https://github.com/XRPLF/rippled.git
synced 2026-03-13 16:22:31 +00:00
Compare commits
22 Commits
develop
...
ximinez/le
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e881e70ff | ||
|
|
56dc85d417 | ||
|
|
6e36944ebc | ||
|
|
64a096130f | ||
|
|
037f3152a7 | ||
|
|
70f535fce2 | ||
|
|
368d79515e | ||
|
|
142aaa7ae3 | ||
|
|
39c397a0fd | ||
|
|
6266899acb | ||
|
|
2a8d0ecca7 | ||
|
|
1fc3f4dedc | ||
|
|
6bb09ee163 | ||
|
|
c679707a39 | ||
|
|
f58a0a551b | ||
|
|
83799db46a | ||
|
|
ef97ac2b7a | ||
|
|
3823dbc74c | ||
|
|
958a7c12c6 | ||
|
|
20d9cb89dd | ||
|
|
e105d59b90 | ||
|
|
8cae6b0adc |
@@ -27,33 +27,6 @@ namespace xrpl {
|
||||
* communicate the interface required of any invariant checker. Any invariant
|
||||
* check implementation should implement the public methods documented here.
|
||||
*
|
||||
* ## Rules for implementing `finalize`
|
||||
*
|
||||
* ### Invariants must run regardless of transaction result
|
||||
*
|
||||
* An invariant's `finalize` method MUST perform meaningful checks even when
|
||||
* the transaction has failed (i.e., `!isTesSuccess(tec)`). The following
|
||||
* pattern is almost certainly wrong and must never be used:
|
||||
*
|
||||
* @code
|
||||
* // WRONG: skipping all checks on failure defeats the purpose of invariants
|
||||
* if (!isTesSuccess(tec))
|
||||
* return true;
|
||||
* @endcode
|
||||
*
|
||||
* The entire purpose of invariants is to detect and prevent the impossible.
|
||||
* A bug or exploit could cause a failed transaction to mutate ledger state in
|
||||
* unexpected ways. Invariants are the last line of defense against such
|
||||
* scenarios.
|
||||
*
|
||||
* In general: an invariant that expects a domain-specific state change to
|
||||
* occur (e.g., a new object being created) should only expect that change
|
||||
* when the transaction succeeded. A failed VaultCreate must not have created
|
||||
* a Vault. A failed LoanSet must not have created a Loan.
|
||||
*
|
||||
* Also be aware that failed transactions, regardless of type, carry no
|
||||
* Privileges. Any privilege-gated checks must therefore also be applied to
|
||||
* failed transactions.
|
||||
*/
|
||||
class InvariantChecker_PROTOTYPE
|
||||
{
|
||||
@@ -75,11 +48,7 @@ public:
|
||||
|
||||
/**
|
||||
* @brief called after all ledger entries have been visited to determine
|
||||
* the final status of the check.
|
||||
*
|
||||
* This method MUST perform meaningful checks even when `tec` indicates a
|
||||
* failed transaction. See the class-level documentation for the rules
|
||||
* governing how failed transactions must be handled.
|
||||
* the final status of the check
|
||||
*
|
||||
* @param tx the transaction being applied
|
||||
* @param tec the current TER result of the transaction
|
||||
|
||||
@@ -107,7 +107,7 @@ CredentialCreate::doApply()
|
||||
return tecEXPIRED;
|
||||
}
|
||||
|
||||
sleCred->setFieldU32(sfExpiration, *optExp);
|
||||
sleCred->setFieldU32(sfExpiration, ctx_.tx.getFieldU32(sfExpiration));
|
||||
}
|
||||
|
||||
auto const sleIssuer = view().peek(keylet::account(account_));
|
||||
|
||||
@@ -676,7 +676,7 @@ AMMWithdraw::equalWithdrawTokens(
|
||||
STAmount const& lpTokens,
|
||||
STAmount const& lpTokensWithdraw,
|
||||
std::uint16_t tfee,
|
||||
FreezeHandling freezeHandling,
|
||||
FreezeHandling freezeHanding,
|
||||
WithdrawAll withdrawAll,
|
||||
XRPAmount const& priorBalance,
|
||||
beast::Journal const& journal)
|
||||
@@ -697,7 +697,7 @@ AMMWithdraw::equalWithdrawTokens(
|
||||
lptAMMBalance,
|
||||
lpTokensWithdraw,
|
||||
tfee,
|
||||
freezeHandling,
|
||||
freezeHanding,
|
||||
WithdrawAll::Yes,
|
||||
priorBalance,
|
||||
journal);
|
||||
@@ -731,7 +731,7 @@ AMMWithdraw::equalWithdrawTokens(
|
||||
lptAMMBalance,
|
||||
tokensAdj,
|
||||
tfee,
|
||||
freezeHandling,
|
||||
freezeHanding,
|
||||
withdrawAll,
|
||||
priorBalance,
|
||||
journal);
|
||||
|
||||
@@ -214,10 +214,8 @@ CreateOffer::checkAcceptAsset(
|
||||
return (flags & tapRETRY) ? TER{terNO_ACCOUNT} : TER{tecNO_ISSUER};
|
||||
}
|
||||
|
||||
// An account cannot create a trustline to itself, so no line can exist
|
||||
// to be frozen. Additionally, an issuer can always accept its own
|
||||
// issuance.
|
||||
if (issue.account == id)
|
||||
// An account can always accept its own issuance.
|
||||
return tesSUCCESS;
|
||||
|
||||
if ((*issuerAccount)[sfFlags] & lsfRequireAuth)
|
||||
@@ -244,6 +242,14 @@ CreateOffer::checkAcceptAsset(
|
||||
}
|
||||
}
|
||||
|
||||
// An account can not create a trustline to itself, so no line can exist
|
||||
// to be frozen. Additionally, an issuer can always accept its own
|
||||
// issuance.
|
||||
if (issue.account == id)
|
||||
{
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
auto const trustLine = view.read(keylet::line(id, issue.account, issue.currency));
|
||||
|
||||
if (!trustLine)
|
||||
|
||||
@@ -995,18 +995,34 @@ computePaymentComponents(
|
||||
XRPL_ASSERT_PARTS(
|
||||
excess >= beast::zero, "xrpl::detail::computePaymentComponents", "excess non-negative");
|
||||
};
|
||||
// Helper to reduce deltas when they collectively exceed a limit.
|
||||
// Order matters: we prefer to reduce interest first (most flexible),
|
||||
// then management fee, then principal (least flexible).
|
||||
auto giveTo = [](Number& component, Number& shortage, Number const& maximum) {
|
||||
if (shortage > beast::zero)
|
||||
{
|
||||
// Put as much of the shortage as we can into the provided part
|
||||
// and the total
|
||||
auto part = std::min(maximum - component, shortage);
|
||||
component += part;
|
||||
shortage -= part;
|
||||
}
|
||||
// If the shortage goes negative, we put too much, which should be
|
||||
// impossible
|
||||
XRPL_ASSERT_PARTS(
|
||||
shortage >= beast::zero,
|
||||
"ripple::detail::computePaymentComponents",
|
||||
"excess non-negative");
|
||||
};
|
||||
auto addressExcess = [&takeFrom](LoanStateDeltas& deltas, Number& excess) {
|
||||
// This order is based on where errors are the least problematic
|
||||
takeFrom(deltas.interest, excess);
|
||||
takeFrom(deltas.managementFee, excess);
|
||||
takeFrom(deltas.principal, excess);
|
||||
};
|
||||
|
||||
// Check if deltas exceed the total outstanding value. This should never
|
||||
// happen due to earlier caps, but handle it defensively.
|
||||
auto addressShortage =
|
||||
[&giveTo](LoanStateDeltas& deltas, Number& shortage, LoanState const& current) {
|
||||
giveTo(deltas.interest, shortage, current.interestDue);
|
||||
giveTo(deltas.managementFee, shortage, current.managementFeeDue);
|
||||
giveTo(deltas.principal, shortage, current.principalOutstanding);
|
||||
};
|
||||
Number totalOverpayment = deltas.total() - currentLedgerState.valueOutstanding;
|
||||
|
||||
if (totalOverpayment > beast::zero)
|
||||
@@ -1034,12 +1050,33 @@ computePaymentComponents(
|
||||
addressExcess(deltas, excess);
|
||||
shortage = -excess;
|
||||
}
|
||||
else if (shortage > beast::zero && totalOverpayment < beast::zero)
|
||||
{
|
||||
// If there's a shortage, and there's room in the loan itself, we can
|
||||
// top up the parts to make the payment correct.
|
||||
shortage = std::min(-totalOverpayment, shortage);
|
||||
addressShortage(deltas, shortage, currentLedgerState);
|
||||
}
|
||||
|
||||
// At this point, shortage >= 0 means we're paying less than the full
|
||||
// periodic payment (due to rounding or component caps).
|
||||
// shortage < 0 would mean we're trying to pay more than allowed (bug).
|
||||
// The shortage should never be negative, which indicates that the parts are
|
||||
// trying to take more than the whole payment. The shortage should not be
|
||||
// positive, either, which indicates that we're not going to take the whole
|
||||
// payment amount. Only the last payment should be allowed to have a
|
||||
// shortage, and that's handled in a special case above.
|
||||
XRPL_ASSERT_PARTS(
|
||||
shortage >= beast::zero, "xrpl::detail::computePaymentComponents", "no shortage or excess");
|
||||
shortage == beast::zero,
|
||||
"ripple::detail::computePaymentComponents",
|
||||
"no shortage or excess");
|
||||
#if LOANCOMPLETE
|
||||
/*
|
||||
// This used to be part of the above assert. It will eventually be removed
|
||||
// if proved accurate
|
||||
||
|
||||
(shortage > beast::zero &&
|
||||
((asset.integral() && shortage < 3) ||
|
||||
(scale - shortage.exponent() > 14)))
|
||||
*/
|
||||
#endif
|
||||
|
||||
// Final validation that all components are valid
|
||||
XRPL_ASSERT_PARTS(
|
||||
|
||||
@@ -2492,11 +2492,10 @@ protected:
|
||||
state.paymentRemaining,
|
||||
broker.params.managementFeeRate);
|
||||
|
||||
BEAST_EXPECTS(
|
||||
paymentComponents.specialCase == detail::PaymentSpecialCase::final ||
|
||||
paymentComponents.trackedValueDelta <= roundedPeriodicPayment,
|
||||
"Delta: " + to_string(paymentComponents.trackedValueDelta) +
|
||||
", periodic payment: " + to_string(roundedPeriodicPayment));
|
||||
BEAST_EXPECT(
|
||||
paymentComponents.trackedValueDelta == roundedPeriodicPayment ||
|
||||
(paymentComponents.specialCase == detail::PaymentSpecialCase::final &&
|
||||
paymentComponents.trackedValueDelta < roundedPeriodicPayment));
|
||||
|
||||
xrpl::LoanState const nextTrueState = computeTheoreticalLoanState(
|
||||
state.periodicPayment,
|
||||
|
||||
Reference in New Issue
Block a user