diff --git a/src/ripple/app/tx/impl/Change.cpp b/src/ripple/app/tx/impl/Change.cpp index 1a78e0815c..c2c8fe1e94 100644 --- a/src/ripple/app/tx/impl/Change.cpp +++ b/src/ripple/app/tx/impl/Change.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -584,10 +585,6 @@ Change::activateXahauGenesis() SetSignerList::removeFromLedger(ctx_.app, sb, accid, j_); // Step 4: install genesis hooks - sle->setFieldU32( - sfOwnerCount, sle->getFieldU32(sfOwnerCount) + genesis_hooks.size()); - sb.update(sle); - if (sb.exists(keylet::hook(accid))) { JLOG(j_.warn()) << "featureXahauGenesis genesis account already has " @@ -598,6 +595,7 @@ Change::activateXahauGenesis() { ripple::STArray hooks{sfHooks, static_cast(genesis_hooks.size())}; int hookCount = 0; + uint32_t hookReserve = 0; for (auto const& [hookOn, wasmBytes, params] : genesis_hooks) { @@ -703,8 +701,14 @@ Change::activateXahauGenesis() } hooks.push_back(hookObj); + + hookReserve += SetHook::computeHookReserve(hookObj); } + sle->setFieldU32( + sfOwnerCount, sle->getFieldU32(sfOwnerCount) + hookReserve); + sb.update(sle); + auto sle = std::make_shared(keylet::hook(accid)); sle->setFieldArray(sfHooks, hooks); sle->setAccountID(sfAccount, accid); @@ -745,6 +749,8 @@ Change::activateXahauGenesis() ripple::STArray hooks{sfHooks, 1}; STObject hookObj{sfHook}; hookObj.setFieldH256(sfHookHash, governHash); + + uint32_t hookReserve = 0; // parameters { std::vector vec; @@ -760,6 +766,7 @@ Change::activateXahauGenesis() sfHookParameters, STArray(vec, sfHookParameters)); } + hookReserve += SetHook::computeHookReserve(hookObj); hooks.push_back(hookObj); auto sle = std::make_shared(hookKL); @@ -786,7 +793,8 @@ Change::activateXahauGenesis() sle->setAccountID(sfRegularKey, noAccount()); sle->setFieldU32(sfFlags, lsfDisableMaster); - sle->setFieldU32(sfOwnerCount, sle->getFieldU32(sfOwnerCount) + 1); + sle->setFieldU32( + sfOwnerCount, sle->getFieldU32(sfOwnerCount) + hookReserve); sb.update(sle); } } diff --git a/src/ripple/app/tx/impl/SetHook.cpp b/src/ripple/app/tx/impl/SetHook.cpp index 72ab85be5d..48ddc5ee56 100644 --- a/src/ripple/app/tx/impl/SetHook.cpp +++ b/src/ripple/app/tx/impl/SetHook.cpp @@ -1221,6 +1221,29 @@ updateHookParameters( return tesSUCCESS; } +/** + * Compute the reserve required for a hook object. + * @param hookObj The hook object to compute the reserve for.(not Transaction + * field, use the Hook object inside the ltHook object.) + * @return The reserve required for the hook object. + */ +uint32_t +SetHook::computeHookReserve(STObject const& hookObj) +{ + if (!hookObj.isFieldPresent(sfHookHash)) + return 0; + + int reserve{1}; + + if (hookObj.isFieldPresent(sfHookParameters)) + reserve += hookObj.getFieldArray(sfHookParameters).size(); + + if (hookObj.isFieldPresent(sfHookGrants)) + reserve += hookObj.getFieldArray(sfHookGrants).size(); + + return reserve; +}; + struct KeyletComparator { bool @@ -1972,28 +1995,14 @@ SetHook::setHook() int oldHookReserve = 0; int newHookReserve = 0; - auto const computeHookReserve = [](STObject const& hookObj) -> int { - if (!hookObj.isFieldPresent(sfHookHash)) - return 0; - - int reserve{1}; - - if (hookObj.isFieldPresent(sfHookParameters)) - reserve += hookObj.getFieldArray(sfHookParameters).size(); - - if (hookObj.isFieldPresent(sfHookGrants)) - reserve += hookObj.getFieldArray(sfHookGrants).size(); - - return reserve; - }; - for (int i = 0; i < hook::maxHookChainLength(); ++i) { if (oldHooks && i < oldHookCount) - oldHookReserve += computeHookReserve(((*oldHooks).get())[i]); + oldHookReserve += + SetHook::computeHookReserve(((*oldHooks).get())[i]); if (i < newHooks.size()) - newHookReserve += computeHookReserve(newHooks[i]); + newHookReserve += SetHook::computeHookReserve(newHooks[i]); } reserveDelta = newHookReserve - oldHookReserve; diff --git a/src/ripple/app/tx/impl/SetHook.h b/src/ripple/app/tx/impl/SetHook.h index ecfce24100..876aeaa3f4 100644 --- a/src/ripple/app/tx/impl/SetHook.h +++ b/src/ripple/app/tx/impl/SetHook.h @@ -91,6 +91,9 @@ class SetHook : public Transactor static HookSetValidation validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj); + static uint32_t + computeHookReserve(STObject const& hookObj); + private: TER setHook(); diff --git a/src/test/app/XahauGenesis_test.cpp b/src/test/app/XahauGenesis_test.cpp index 8353a3ce9a..35cd8ca72c 100644 --- a/src/test/app/XahauGenesis_test.cpp +++ b/src/test/app/XahauGenesis_test.cpp @@ -139,7 +139,9 @@ struct XahauGenesis_test : public beast::unit_test::suite false, // means the calling test already burned some of the genesis bool skipTests = false, bool const testFlag = false, - bool const badNetID = false) + bool const badNetID = false, + uint32_t const expectedOwnerCount = + 10 /** testFlag ? 10 : 14 (default) */) { using namespace jtx; @@ -247,7 +249,10 @@ struct XahauGenesis_test : public beast::unit_test::suite BEAST_EXPECT( genesisAccRoot->getFieldAmount(sfBalance) == XahauGenesis::GenesisAmount); - BEAST_EXPECT(genesisAccRoot->getFieldU32(sfOwnerCount) == 2); + BEAST_EXPECT( + genesisAccRoot->getFieldU32(sfOwnerCount) == !testFlag + ? expectedOwnerCount + : 14); // ensure the definitions are correctly set { @@ -583,7 +588,14 @@ struct XahauGenesis_test : public beast::unit_test::suite toBase58(t), membersStr); } - activate(__LINE__, env, true, false, true); + activate( + __LINE__, + env, + true, + false, + true, + {}, + 3 /* IRR,IRD,IMC */ + members.size() + tables.size()); env.close(); env.close(); @@ -2235,6 +2247,8 @@ struct XahauGenesis_test : public beast::unit_test::suite BEAST_EXPECT(!!hookLE); uint256 const ns = beast::zero; uint8_t mc = 0; + uint8_t paramsCount = 0; + if (hookLE) { auto const hooksArray = hookLE->getFieldArray(sfHooks); @@ -2242,6 +2256,9 @@ struct XahauGenesis_test : public beast::unit_test::suite hooksArray.size() == 1 && hooksArray[0].getFieldH256(sfHookHash) == governHookHash); + paramsCount = + hooksArray[0].getFieldArray(sfHookParameters).size(); + for (Account const* m : members) { auto const mVec = vecFromAcc(*m); @@ -2308,7 +2325,9 @@ struct XahauGenesis_test : public beast::unit_test::suite BEAST_EXPECT(!!root); if (root) { - BEAST_EXPECT(root->getFieldU32(sfOwnerCount) == mc * 2 + 2); + BEAST_EXPECT( + root->getFieldU32(sfOwnerCount) == + mc * 2 + 2 + paramsCount); BEAST_EXPECT(root->getFieldU32(sfFlags) & lsfDisableMaster); BEAST_EXPECT(root->getAccountID(sfRegularKey) == noAccount()); }