From f48488b8f7d4b06c2f7bf4c5e5f51815d6648b5b Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Tue, 15 Apr 2025 09:05:00 -0400 Subject: [PATCH] Experiment: Add invariant to enforce directory node population --- src/xrpld/app/tx/detail/InvariantCheck.cpp | 38 ++++++++++++++++++++++ src/xrpld/app/tx/detail/InvariantCheck.h | 27 ++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/xrpld/app/tx/detail/InvariantCheck.cpp b/src/xrpld/app/tx/detail/InvariantCheck.cpp index f7f67ee1d6..1f3711e5a2 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.cpp +++ b/src/xrpld/app/tx/detail/InvariantCheck.cpp @@ -3115,4 +3115,42 @@ ValidVault::finalize( return true; } +//------------------------------------------------------------------------------ + +void +NoEmptyDirectory::visitEntry( + bool isDelete, + std::shared_ptr const& before, + std::shared_ptr const& after) +{ + if (isDelete) + return; + if (before && before->getType() != ltDIR_NODE) + return; + if (after && after->getType() != ltDIR_NODE) + return; + if (!after->isFieldPresent(sfOwner)) + // Not an account dir + return; + + bad_ = after->at(sfIndexes).empty(); +} + +bool +NoEmptyDirectory::finalize( + STTx const& tx, + TER const result, + XRPAmount const, + ReadView const& view, + beast::Journal const& j) +{ + if (bad_) + { + JLOG(j.fatal()) << "Invariant failed: empty owner directory."; + return false; + } + + return true; +} + } // namespace ripple diff --git a/src/xrpld/app/tx/detail/InvariantCheck.h b/src/xrpld/app/tx/detail/InvariantCheck.h index 97d51f0fab..c890a3c840 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.h +++ b/src/xrpld/app/tx/detail/InvariantCheck.h @@ -802,6 +802,30 @@ public: beast::Journal const&); }; +/** + * @brief Invariants: An account's directory should never be empty + * + */ +class NoEmptyDirectory +{ + bool bad_ = false; + +public: + void + visitEntry( + bool, + std::shared_ptr const&, + std::shared_ptr const&); + + bool + finalize( + STTx const&, + TER const, + XRPAmount const, + ReadView const&, + beast::Journal const&); +}; + // additional invariant checks can be declared above and then added to this // tuple using InvariantChecks = std::tuple< @@ -825,7 +849,8 @@ using InvariantChecks = std::tuple< ValidPermissionedDEX, ValidAMM, ValidPseudoAccounts, - ValidVault>; + ValidVault, + NoEmptyDirectory>; /** * @brief get a tuple of all invariant checks