mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-06 18:26:51 +00:00
Compare commits
3 Commits
bthomee/jq
...
tapanito/d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
110587862e | ||
|
|
f2b226f36a | ||
|
|
943c92ca1e |
@@ -1250,16 +1250,30 @@ hasInvalidAmount(STBase const& field, int depth, beast::Journal j)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (auto const amount = dynamic_cast<STAmount const*>(&field))
|
||||
return !isLegalMPT(*amount) || !isLegalNet(*amount);
|
||||
// Dispatch on the serialized type tag rather than RTTI: this is on the invariant-checking path
|
||||
// and a dynamic_cast chain over every field of every modified entry is measurably expensive.
|
||||
// The object-like tags below all denote STObject subclasses (STLedgerEntry, STTx), so the
|
||||
// downcast is sound; nested fields are only ever plain STI_OBJECT / STI_ARRAY containers.
|
||||
// safeDowncast keeps a dynamic_cast validity assert in debug builds while compiling to
|
||||
// static_cast in release.
|
||||
switch (field.getSType())
|
||||
{
|
||||
case STI_AMOUNT: {
|
||||
auto const& amount = safeDowncast<STAmount const&>(field);
|
||||
return !isLegalMPT(amount) || !isLegalNet(amount);
|
||||
}
|
||||
|
||||
if (auto const object = dynamic_cast<STObject const*>(&field))
|
||||
return hasInvalidAmount(*object, depth + 1, j);
|
||||
case STI_OBJECT:
|
||||
case STI_LEDGERENTRY:
|
||||
case STI_TRANSACTION:
|
||||
return hasInvalidAmount(safeDowncast<STObject const&>(field), depth + 1, j);
|
||||
|
||||
if (auto const array = dynamic_cast<STArray const*>(&field))
|
||||
return hasInvalidAmount(*array, depth + 1, j);
|
||||
case STI_ARRAY:
|
||||
return hasInvalidAmount(safeDowncast<STArray const&>(field), depth + 1, j);
|
||||
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -1172,21 +1172,17 @@ Transactor::checkTransactionInvariants(TER result, XRPAmount fee)
|
||||
[[nodiscard]] TER
|
||||
Transactor::checkInvariants(TER result, XRPAmount fee)
|
||||
{
|
||||
// Transaction invariants first (more specific). These check post-conditions of the specific
|
||||
// transaction. If these fail, the transaction's core logic is wrong.
|
||||
auto const txResult = checkTransactionInvariants(result, fee);
|
||||
|
||||
// Protocol invariants second (broader). These check properties that must hold regardless of
|
||||
// transaction type.
|
||||
auto const protoResult = ctx_.checkInvariants(result, fee);
|
||||
|
||||
// Fail if either check failed. tef (fatal) takes priority over tec.
|
||||
if (protoResult == tefINVARIANT_FAILED)
|
||||
return tefINVARIANT_FAILED;
|
||||
if (txResult == tecINVARIANT_FAILED || protoResult == tecINVARIANT_FAILED)
|
||||
return tecINVARIANT_FAILED;
|
||||
|
||||
return result;
|
||||
/*
|
||||
* DISABLED for 3.2.0 — Must be re-introduced for 3.3.0
|
||||
*
|
||||
* Transaction invariants are disabled due to a performance regression:
|
||||
* the two-pass design (transaction-specific invariants + protocol invariants)
|
||||
* iterates over modified ledger entries twice per transaction.
|
||||
*
|
||||
* Until resolved, only protocol invariants are checked (delegated to ctx_).
|
||||
* This is safe because all transaction invariants in 3.2.0 are no-ops.
|
||||
*/
|
||||
return ctx_.checkInvariants(result, fee);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
ApplyResult
|
||||
|
||||
Reference in New Issue
Block a user