From c02d85fd05d83dda5e95b5a138972165a78dc091 Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Tue, 15 Apr 2025 09:05:00 -0400 Subject: [PATCH 1/2] 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 d93378d3cde..5dfb893a16d 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.cpp +++ b/src/xrpld/app/tx/detail/InvariantCheck.cpp @@ -2022,4 +2022,42 @@ ValidAMM::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 529c05ce0e9..2127e15ae8a 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.h +++ b/src/xrpld/app/tx/detail/InvariantCheck.h @@ -704,6 +704,30 @@ class ValidAMM beast::Journal const&) 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< @@ -725,7 +749,8 @@ using InvariantChecks = std::tuple< ValidMPTIssuance, ValidPermissionedDomain, ValidPermissionedDEX, - ValidAMM>; + ValidAMM, + NoEmptyDirectory>; /** * @brief get a tuple of all invariant checks From 513d04e81374847a00758d36093e8aa697147fbc Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Tue, 15 Apr 2025 09:55:44 -0400 Subject: [PATCH 2/2] Experiment: Always delete the root --- src/xrpld/ledger/detail/ApplyView.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xrpld/ledger/detail/ApplyView.cpp b/src/xrpld/ledger/detail/ApplyView.cpp index 3191b47cbbf..468bc5234ee 100644 --- a/src/xrpld/ledger/detail/ApplyView.cpp +++ b/src/xrpld/ledger/detail/ApplyView.cpp @@ -193,6 +193,7 @@ ApplyView::dirRemove( uint256 const& key, bool keepRoot) { + keepRoot = false; auto node = peek(keylet::page(directory, page)); if (!node)