From 46130fe14f8cdebac70c66844ad63039f16af3ae Mon Sep 17 00:00:00 2001 From: Richard Holland Date: Fri, 11 Mar 2022 13:02:10 +0000 Subject: [PATCH] add sfHookNamespaces array to account root --- src/ripple/app/tx/impl/SetHook.cpp | 65 +++++++++++----------- src/ripple/app/tx/impl/SetHook.h | 2 +- src/ripple/app/tx/impl/applyHook.cpp | 62 +++++++++++++++++++-- src/ripple/protocol/SField.h | 1 + src/ripple/protocol/impl/LedgerFormats.cpp | 4 +- src/ripple/protocol/impl/SField.cpp | 1 + 6 files changed, 96 insertions(+), 39 deletions(-) diff --git a/src/ripple/app/tx/impl/SetHook.cpp b/src/ripple/app/tx/impl/SetHook.cpp index 0099214b6..160ba06f2 100644 --- a/src/ripple/app/tx/impl/SetHook.cpp +++ b/src/ripple/app/tx/impl/SetHook.cpp @@ -1467,11 +1467,13 @@ SetHook::destroyNamespace( SetHookCtx& ctx, ApplyView& view, const AccountID& account, - const Keylet & dirKeylet // the keylet of the namespace directory + uint256 ns ) { JLOG(ctx.j.trace()) << "HookSet[" << HS_ACC() << "]: DeleteState " - << "Destroying Hook Namespace for " << account << " namespace keylet " << dirKeylet.key; + << "Destroying Hook Namespace for " << account << " namespace " << ns; + + Keylet dirKeylet = keylet::hookStateDir(account, ns); std::shared_ptr sleDirNode{}; unsigned int uDirEntry{0}; @@ -1506,7 +1508,7 @@ SetHook::destroyNamespace( uint32_t stateCount =sleAccount->getFieldU32(sfHookStateCount); uint32_t oldStateCount = stateCount; - std::vector> toDelete {sleDir->getFieldV256(sfIndexes).size()}; + std::vector toDelete {sleDir->getFieldV256(sfIndexes).size()}; do { // Make sure any directory node types that we find are the kind @@ -1535,7 +1537,8 @@ SetHook::destroyNamespace( return tefBAD_LEDGER; } - toDelete.push_back(uint256::fromVoidChecked(itemKeylet.key)); + + toDelete.push_back(uint256::fromVoid(itemKeylet.key.data())); } while (cdirNext(view, dirKeylet.key, sleDirNode, uDirEntry, dirEntry)); @@ -1543,30 +1546,20 @@ SetHook::destroyNamespace( // delete it! for (auto const& itemKey: toDelete) { - // should never happen - if (!itemKey) - { - JLOG(ctx.j.fatal()) - << "HookSet[" << HS_ACC() << "]: DeleteState " - << "directory entry in ledger " << view.seq() << " " - << "was invalid key fromVoidChecked."; - return tefBAD_LEDGER; - } - - auto const& sleItem = view.peek({ltHOOK_STATE, *itemKey}); + auto const& sleItem = view.peek({ltHOOK_STATE, itemKey}); if (!sleItem) { JLOG(ctx.j.warn()) << "HookSet[" << HS_ACC() << "]: DeleteState " << "Namespace ltHOOK_STATE entry was not found in ledger: " - << *itemKey; + << itemKey; continue; } auto const hint = (*sleItem)[sfOwnerNode]; - if (!itemKey || !view.dirRemove(dirKeylet, hint, *itemKey, false)) + if (!view.dirRemove(dirKeylet, hint, itemKey, false)) { JLOG(ctx.j.fatal()) << "HookSet[" << HS_ACC() << "]: DeleteState " @@ -1589,6 +1582,24 @@ SetHook::destroyNamespace( sleAccount->setFieldU32(sfHookStateCount, stateCount); + STVector256 const& vec = sleAccount->getFieldV256(sfHookNamespaces); + if (vec.size() - 1 == 0) + { + sleAccount->makeFieldAbsent(sfHookNamespaces); + } + else + { + std::vector nv { vec.size() - 1 }; + + for (uint256 u : vec.value()) + if (u != ns) + nv.push_back(u); + + sleAccount->setFieldV256(sfHookNamespaces, STVector256 { std::move(nv) } ); + } + + view.update(sleAccount); + return tesSUCCESS; } @@ -1648,7 +1659,7 @@ createOrReuseNamespace(ripple::Keylet& newDirKeylet) return tesSUSCCESS; } //if (oldDirSLE) - // reduceReferenceCount(oldDirSLE, (flag & hsoNSDELETE) ? dirsToDestroy : std::nullopt); + // reduceReferenceCount(oldDirSLE, (flag & hsoNSDELETE) ? namespacesToDestroy : std::nullopt); */ TER @@ -1768,7 +1779,7 @@ SetHook::setHook() } std::set defsToDestroy {}; - std::set dirsToDestroy {}; + std::set namespacesToDestroy {}; int hookSetNumber = -1; auto const& hookSets = ctx.tx.getFieldArray(sfHooks); @@ -1888,12 +1899,12 @@ SetHook::setHook() else if(op == hsoNSDELETE && newDirKeylet) { printf("Marking a namespace for destruction.... NSDELETE\n"); - dirsToDestroy.emplace(*newDirKeylet); + namespacesToDestroy.emplace(*newNamespace); } else if (oldDirKeylet) { printf("Marking a namespace for destruction.... non-NSDELETE\n"); - dirsToDestroy.emplace(*oldDirKeylet); + namespacesToDestroy.emplace(*oldNamespace); } else { @@ -2165,16 +2176,8 @@ SetHook::setHook() { // clean up any Namespace directories marked for deletion and any zero reference Hook Definitions - - // dirs - for (auto const& p : dirsToDestroy) - { - auto const& sle = view().peek(p); - if (!sle) - continue; - printf("==>> Destroying namespace\n"); - destroyNamespace(ctx, view(), account_, p); - } + for (auto const& ns : namespacesToDestroy) + destroyNamespace(ctx, view(), account_, ns); // defs diff --git a/src/ripple/app/tx/impl/SetHook.h b/src/ripple/app/tx/impl/SetHook.h index 2c315a803..b17baa632 100644 --- a/src/ripple/app/tx/impl/SetHook.h +++ b/src/ripple/app/tx/impl/SetHook.h @@ -87,7 +87,7 @@ private: SetHookCtx& ctx, ApplyView& view, const AccountID& account, - const Keylet & dirKeylet // the keylet of the namespace directory + uint256 ns ); TER diff --git a/src/ripple/app/tx/impl/applyHook.cpp b/src/ripple/app/tx/impl/applyHook.cpp index 0f303d754..792d6832c 100644 --- a/src/ripple/app/tx/impl/applyHook.cpp +++ b/src/ripple/app/tx/impl/applyHook.cpp @@ -313,7 +313,7 @@ bool hook::canHook(ripple::TxType txType, uint64_t hookOn) { } -// Update HookState ledger objects for the hook... only called after accept() or reject() +// Update HookState ledger objects for the hook... only called after accept() or rollback() // assumes the specified acc has already been checked for authoriation (hook grants) TER hook::setHookState( @@ -357,11 +357,12 @@ hook::setHookState( return tefBAD_LEDGER; auto const hint = (*hookState)[sfOwnerNode]; - // Remove the node from the namespace directory if (!view.dirRemove(hookStateDirKeylet, hint, hookStateKeylet.key, false)) return tefBAD_LEDGER; + bool nsDestroyed = !view.peek(hookStateDirKeylet); + // remove the actual hook state obj view.erase(hookState); @@ -374,7 +375,35 @@ hook::setHookState( adjustOwnerCount(view, sleAccount, -1, j); sleAccount->setFieldU32(sfHookStateCount, stateCount); + + + if (nsDestroyed) + { + STVector256 const& vec = sleAccount->getFieldV256(sfHookNamespaces); + if (vec.size() - 1 == 0) + sleAccount->makeFieldAbsent(sfHookNamespaces); + else + { + std::vector nv { vec.size() - 1 }; + for (uint256 u : vec.value()) + if (u != ns) + nv.push_back(u); + sleAccount->setFieldV256(sfHookNamespaces, STVector256{std::move(nv)}); + } + } + view.update(sleAccount); + + /* + // if the root page of this namespace was removed then also remove the root page + // from the owner directory + if (!view.peek(hookStateDirKeylet) && rootHint) + { + if (!view.dirRemove(keylet::ownerDir(acc), *rootHint, hookStateDirKeylet.key, false)) + return tefBAD_LEDGER; + } + */ + return tesSUCCESS; } @@ -418,22 +447,43 @@ hook::setHookState( if (createNew) { - // Add the hook to the account's directory if it wasn't there already + bool nsExists = !!view.peek(hookStateDirKeylet); + auto const page = view.dirInsert( hookStateDirKeylet, hookStateKeylet.key, describeOwnerDir(acc)); - if (!page) return tecDIR_FULL; - + hookState->setFieldU64(sfOwnerNode, *page); - + // add new data to ledger view.insert(hookState); + + // update namespace vector where necessary + if (!nsExists) + { + if (!sleAccount->isFieldPresent(sfHookNamespaces)) + { + sleAccount->setFieldV256(sfHookNamespaces, STVector256{std::vector{ns}}); + view.update(sleAccount); + } + else + { + STVector256 const& vec = sleAccount->getFieldV256(sfHookNamespaces); + std::vector nv { vec.value() }; + nv.push_back(ns); + sleAccount->setFieldV256(sfHookNamespaces, STVector256{std::move(nv)}); + view.update(sleAccount); + } + } + } else + { view.update(hookState); + } return tesSUCCESS; } diff --git a/src/ripple/protocol/SField.h b/src/ripple/protocol/SField.h index 6397990fb..0e38e5b94 100644 --- a/src/ripple/protocol/SField.h +++ b/src/ripple/protocol/SField.h @@ -531,6 +531,7 @@ extern SF_VECTOR256 const sfIndexes; extern SF_VECTOR256 const sfHashes; extern SF_VECTOR256 const sfAmendments; extern SF_VECTOR256 const sfTokenOffers; +extern SF_VECTOR256 const sfHookNamespaces; // inner object // OBJECT/1 is reserved for end of object diff --git a/src/ripple/protocol/impl/LedgerFormats.cpp b/src/ripple/protocol/impl/LedgerFormats.cpp index d4bd2ea56..9824a5264 100644 --- a/src/ripple/protocol/impl/LedgerFormats.cpp +++ b/src/ripple/protocol/impl/LedgerFormats.cpp @@ -54,7 +54,8 @@ LedgerFormats::LedgerFormats() {sfDomain, soeOPTIONAL}, {sfTickSize, soeOPTIONAL}, {sfTicketCount, soeOPTIONAL}, - {sfHookStateCount, soeOPTIONAL} + {sfHookStateCount, soeOPTIONAL}, + {sfHookNamespaces, soeOPTIONAL} }, commonFields); @@ -68,6 +69,7 @@ LedgerFormats::LedgerFormats() {sfTakerGetsIssuer, soeOPTIONAL}, // for order book directories {sfExchangeRate, soeOPTIONAL}, // for order book directories {sfReferenceCount, soeOPTIONAL}, // for hook state directories + {sfOwnerNode, soeOPTIONAL}, // for directories that are members of other directories {sfIndexes, soeREQUIRED}, {sfRootIndex, soeREQUIRED}, {sfIndexNext, soeOPTIONAL}, diff --git a/src/ripple/protocol/impl/SField.cpp b/src/ripple/protocol/impl/SField.cpp index 634db7235..d300db4c4 100644 --- a/src/ripple/protocol/impl/SField.cpp +++ b/src/ripple/protocol/impl/SField.cpp @@ -280,6 +280,7 @@ CONSTRUCT_TYPED_SFIELD(sfIndexes, "Indexes", VECTOR25 CONSTRUCT_TYPED_SFIELD(sfHashes, "Hashes", VECTOR256, 2); CONSTRUCT_TYPED_SFIELD(sfAmendments, "Amendments", VECTOR256, 3); CONSTRUCT_TYPED_SFIELD(sfTokenOffers, "TokenOffers", VECTOR256, 4); +CONSTRUCT_TYPED_SFIELD(sfHookNamespaces, "HookNamespaces", VECTOR256, 5); // path set CONSTRUCT_UNTYPED_SFIELD(sfPaths, "Paths", PATHSET, 1);