#include #include namespace xrpl::test::jtx { /** Directory operations. */ namespace directory { auto bumpLastPage( Env& env, std::uint64_t newLastPage, Keylet directory, std::function adjust) -> Expected { Expected res{}; env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) -> bool { Sandbox sb(&view, tapNONE); // Find the root page auto sleRoot = sb.peek(directory); if (!sleRoot) { res = Unexpected(DirectoryRootNotFound); return false; } // Find last page auto const lastIndex = sleRoot->getFieldU64(sfIndexPrevious); if (lastIndex == 0) { res = Unexpected(DirectoryTooSmall); return false; } if (sb.exists(keylet::page(directory, newLastPage))) { res = Unexpected(DirectoryPageDuplicate); return false; } if (lastIndex >= newLastPage) { res = Unexpected(InvalidLastPage); return false; } auto slePage = sb.peek(keylet::page(directory, lastIndex)); if (!slePage) { res = Unexpected(DirectoryPageNotFound); return false; } // Copy its data and delete the page auto indexes = slePage->getFieldV256(sfIndexes); auto prevIndex = slePage->at(~sfIndexPrevious); auto owner = slePage->at(~sfOwner); sb.erase(slePage); // Create new page to replace slePage auto sleNew = std::make_shared(keylet::page(directory, newLastPage)); sleNew->setFieldH256(sfRootIndex, directory.key); sleNew->setFieldV256(sfIndexes, indexes); if (owner) sleNew->setAccountID(sfOwner, *owner); if (prevIndex) sleNew->setFieldU64(sfIndexPrevious, *prevIndex); sb.insert(sleNew); // Adjust root previous and previous node's next sleRoot->setFieldU64(sfIndexPrevious, newLastPage); if (prevIndex.value_or(0) == 0) { sleRoot->setFieldU64(sfIndexNext, newLastPage); } else { auto slePrev = sb.peek(keylet::page(directory, *prevIndex)); if (!slePrev) { res = Unexpected(DirectoryPageNotFound); return false; } slePrev->setFieldU64(sfIndexNext, newLastPage); sb.update(slePrev); } sb.update(sleRoot); // Fixup page numbers in the objects referred by indexes if (adjust) { for (auto const key : indexes) { if (!adjust(sb, key, newLastPage)) { res = Unexpected(AdjustmentError); return false; } } } sb.apply(view); return true; }); return res; } bool adjustOwnerNode(ApplyView& view, uint256 key, std::uint64_t page) { auto sle = view.peek({ltANY, key}); if (sle && sle->isFieldPresent(sfOwnerNode)) { sle->setFieldU64(sfOwnerNode, page); view.update(sle); return true; } return false; } } // namespace directory } // namespace xrpl::test::jtx