mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-06 18:26:51 +00:00
128 lines
3.4 KiB
C++
128 lines
3.4 KiB
C++
#include <test/jtx/directory.h>
|
|
|
|
#include <xrpl/ledger/Sandbox.h>
|
|
|
|
namespace xrpl::test::jtx {
|
|
|
|
/** Directory operations. */
|
|
namespace directory {
|
|
|
|
auto
|
|
bumpLastPage(
|
|
Env& env,
|
|
std::uint64_t newLastPage,
|
|
Keylet directory,
|
|
std::function<bool(ApplyView&, uint256, std::uint64_t)> adjust) -> Expected<void, Error>
|
|
{
|
|
Expected<void, Error> 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<Error>(DirectoryRootNotFound);
|
|
return false;
|
|
}
|
|
|
|
// Find last page
|
|
auto const lastIndex = sleRoot->getFieldU64(sfIndexPrevious);
|
|
if (lastIndex == 0)
|
|
{
|
|
res = Unexpected<Error>(DirectoryTooSmall);
|
|
return false;
|
|
}
|
|
|
|
if (sb.exists(keylet::page(directory, newLastPage)))
|
|
{
|
|
res = Unexpected<Error>(DirectoryPageDuplicate);
|
|
return false;
|
|
}
|
|
|
|
if (lastIndex >= newLastPage)
|
|
{
|
|
res = Unexpected<Error>(InvalidLastPage);
|
|
return false;
|
|
}
|
|
|
|
auto slePage = sb.peek(keylet::page(directory, lastIndex));
|
|
if (!slePage)
|
|
{
|
|
res = Unexpected<Error>(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<SLE>(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<Error>(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<Error>(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
|