mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-10 04:06:59 +00:00
feat: Move VaultDelete invariants from ValidVault to VaultDelete
This commit is contained in:
@@ -67,10 +67,15 @@ public:
|
||||
[[nodiscard]] std::optional<Shares>
|
||||
findShares(uint192 const& mptID) const;
|
||||
|
||||
/** Find deleted shares in beforeMPTs_ whose mptID matches. */
|
||||
[[nodiscard]] std::optional<Shares>
|
||||
findDeletedShares(uint192 const& mptID) const;
|
||||
|
||||
private:
|
||||
std::vector<Vault> afterVault_;
|
||||
std::vector<Vault> beforeVault_;
|
||||
std::vector<Shares> afterMPTs_;
|
||||
std::vector<Shares> beforeMPTs_;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
#include <xrpl/tx/invariants/VaultInvariantData.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -32,6 +33,9 @@ public:
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
|
||||
private:
|
||||
VaultInvariantData data_;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
@@ -339,51 +338,8 @@ ValidVault::finalize(
|
||||
return !enforce; // That's all we can do here
|
||||
}
|
||||
|
||||
// Note, if afterVault_ is empty then we know that beforeVault_ is not
|
||||
// empty, as enforced at the top of this function
|
||||
auto const& beforeVault = beforeVault_[0];
|
||||
|
||||
// At this moment we only know a vault is being deleted and there
|
||||
// might be some MPTokenIssuance objects which are deleted in the
|
||||
// same transaction. Find the one matching this vault.
|
||||
auto const deletedShares = [&]() -> std::optional<Shares> {
|
||||
for (auto const& e : beforeMPTs_)
|
||||
{
|
||||
if (e.share.getMptID() == beforeVault.shareMPTID)
|
||||
return e;
|
||||
}
|
||||
return std::nullopt;
|
||||
}();
|
||||
|
||||
if (!deletedShares)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: deleted vault must also "
|
||||
"delete shares";
|
||||
XRPL_ASSERT(enforce, "xrpl::ValidVault::finalize : shares deletion invariant");
|
||||
return !enforce; // That's all we can do here
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
if (deletedShares->sharesTotal != 0)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: deleted vault must have no "
|
||||
"shares outstanding";
|
||||
result = false;
|
||||
}
|
||||
if (beforeVault.assetsTotal != kZero)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: deleted vault must have no "
|
||||
"assets outstanding";
|
||||
result = false;
|
||||
}
|
||||
if (beforeVault.assetsAvailable != kZero)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: deleted vault must have no "
|
||||
"assets available";
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
// Delete-specific checks now live in VaultDelete::finalizeInvariants.
|
||||
return true;
|
||||
}
|
||||
if (txnType == ttVAULT_DELETE)
|
||||
{
|
||||
|
||||
@@ -5,8 +5,11 @@
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STNumber.h> // IWYU pragma: keep
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
VaultInvariantData::Vault
|
||||
@@ -51,6 +54,9 @@ VaultInvariantData::visitEntry(bool isDelete, SLE::const_ref before, SLE::const_
|
||||
if (before && before->getType() == ltVAULT)
|
||||
beforeVault_.push_back(Vault::make(*before));
|
||||
|
||||
if (before && before->getType() == ltMPTOKEN_ISSUANCE)
|
||||
beforeMPTs_.push_back(Shares::make(*before));
|
||||
|
||||
if (!isDelete && after)
|
||||
{
|
||||
switch (after->getType())
|
||||
@@ -77,4 +83,15 @@ VaultInvariantData::findShares(uint192 const& mptID) const
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<VaultInvariantData::Shares>
|
||||
VaultInvariantData::findDeletedShares(uint192 const& mptID) const
|
||||
{
|
||||
for (auto const& s : beforeMPTs_)
|
||||
{
|
||||
if (s.share.getMptID() == mptID)
|
||||
return s;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
#include <xrpl/tx/transactors/vault/VaultDelete.h>
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/Number.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
@@ -211,15 +215,76 @@ VaultDelete::doApply()
|
||||
}
|
||||
|
||||
void
|
||||
VaultDelete::visitInvariantEntry(bool, SLE::const_ref, SLE::const_ref)
|
||||
VaultDelete::visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after)
|
||||
{
|
||||
// No transaction-specific invariants yet (future work).
|
||||
data_.visitEntry(isDelete, before, after);
|
||||
}
|
||||
|
||||
bool
|
||||
VaultDelete::finalizeInvariants(STTx const&, TER, XRPAmount, ReadView const&, beast::Journal const&)
|
||||
VaultDelete::finalizeInvariants(
|
||||
STTx const&,
|
||||
TER result,
|
||||
XRPAmount,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j)
|
||||
{
|
||||
// No transaction-specific invariants yet (future work).
|
||||
bool const enforce = view.rules().enabled(featureSingleAssetVault);
|
||||
|
||||
if (!isTesSuccess(result))
|
||||
return true;
|
||||
|
||||
static constexpr Number kZero{};
|
||||
|
||||
// VaultDelete must have deleted the vault; if it still exists, something
|
||||
// went wrong.
|
||||
if (!data_.afterVaults().empty())
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: vault not deleted by VaultDelete";
|
||||
XRPL_ASSERT(enforce, "xrpl::VaultDelete::finalizeInvariants : vault not deleted invariant");
|
||||
return !enforce;
|
||||
}
|
||||
|
||||
// Nothing to check if the vault was never in the before-set (e.g. a
|
||||
// test that omits the vault entry entirely).
|
||||
if (data_.beforeVaults().empty())
|
||||
return true;
|
||||
|
||||
auto const& beforeVault = data_.beforeVaults()[0];
|
||||
|
||||
auto const deletedShares = data_.findDeletedShares(beforeVault.shareMPTID);
|
||||
if (!deletedShares)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: deleted vault must also delete shares";
|
||||
XRPL_ASSERT(enforce, "xrpl::VaultDelete::finalizeInvariants : shares deletion invariant");
|
||||
return !enforce;
|
||||
}
|
||||
|
||||
bool result2 = true;
|
||||
|
||||
if (deletedShares->sharesTotal != 0)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: deleted vault must have no shares outstanding";
|
||||
result2 = false;
|
||||
}
|
||||
|
||||
if (beforeVault.assetsTotal != kZero)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: deleted vault must have no assets outstanding";
|
||||
result2 = false;
|
||||
}
|
||||
|
||||
if (beforeVault.assetsAvailable != kZero)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: deleted vault must have no assets available";
|
||||
result2 = false;
|
||||
}
|
||||
|
||||
if (!result2)
|
||||
{
|
||||
XRPL_ASSERT(enforce, "xrpl::VaultDelete::finalizeInvariants : vault delete invariants");
|
||||
return !enforce;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user