mirror of
https://github.com/Xahau/xahaud.git
synced 2026-06-04 01:06:37 +00:00
add ExtendedHookState
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Rules.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
@@ -28,6 +30,8 @@ enum HookEmissionFlags : uint16_t {
|
||||
};
|
||||
} // namespace ripple
|
||||
|
||||
using namespace ripple;
|
||||
|
||||
namespace hook {
|
||||
// RH TODO: put these somewhere better, and allow rules to be fed in
|
||||
inline uint32_t
|
||||
@@ -43,8 +47,12 @@ maxHookParameterValueSize(void)
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
maxHookStateDataSize(void)
|
||||
maxHookStateDataSize(Rules const& rules)
|
||||
{
|
||||
if (rules.enabled(featureExtendedHookState))
|
||||
{
|
||||
return 2048U;
|
||||
}
|
||||
return 256U;
|
||||
}
|
||||
|
||||
|
||||
@@ -461,7 +461,9 @@ apply(
|
||||
struct HookContext;
|
||||
|
||||
uint32_t
|
||||
computeHookStateOwnerCount(uint32_t hookStateCount);
|
||||
computeHookStateOwnerCount(Blob hookStateData);
|
||||
uint32_t
|
||||
computeHookStateOwnerCount(Slice hookStateData);
|
||||
|
||||
int64_t
|
||||
computeExecutionFee(uint64_t instructionCount);
|
||||
|
||||
@@ -853,9 +853,15 @@ parseCurrency(uint8_t* cu_ptr, uint32_t cu_len)
|
||||
}
|
||||
|
||||
uint32_t
|
||||
hook::computeHookStateOwnerCount(uint32_t hookStateCount)
|
||||
hook::computeHookStateOwnerCount(Blob hookStateData)
|
||||
{
|
||||
return hookStateCount;
|
||||
return std::floor((hookStateData.size() - 1) / 256) + 1;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
hook::computeHookStateOwnerCount(Slice hookStateData)
|
||||
{
|
||||
return std::floor((hookStateData.size() - 1) / 256) + 1;
|
||||
}
|
||||
|
||||
inline int64_t
|
||||
@@ -1047,14 +1053,14 @@ hook::setHookState(
|
||||
return tefINTERNAL;
|
||||
|
||||
// if the blob is too large don't set it
|
||||
if (data.size() > hook::maxHookStateDataSize())
|
||||
if (data.size() > hook::maxHookStateDataSize(view.rules()))
|
||||
return temHOOK_DATA_TOO_LARGE;
|
||||
|
||||
auto hookStateKeylet = ripple::keylet::hookState(acc, key, ns);
|
||||
auto hookStateDirKeylet = ripple::keylet::hookStateDir(acc, ns);
|
||||
|
||||
uint32_t stateCount = sleAccount->getFieldU32(sfHookStateCount);
|
||||
uint32_t oldStateReserve = computeHookStateOwnerCount(stateCount);
|
||||
uint32_t newHookStateCount = sleAccount->getFieldU32(sfHookStateCount);
|
||||
uint32_t oldHookStateCount = newHookStateCount;
|
||||
|
||||
auto hookState = view.peek(hookStateKeylet);
|
||||
|
||||
@@ -1082,16 +1088,22 @@ hook::setHookState(
|
||||
view.erase(hookState);
|
||||
|
||||
// adjust state object count
|
||||
if (stateCount > 0)
|
||||
--stateCount; // guard this because in the "impossible" event it is
|
||||
// already 0 we'll wrap back to int_max
|
||||
|
||||
Blob deletedStateData = hookState->getFieldVL(sfHookStateData);
|
||||
uint32_t deleteOwnerCount =
|
||||
computeHookStateOwnerCount(deletedStateData);
|
||||
if (newHookStateCount >= deleteOwnerCount)
|
||||
{
|
||||
newHookStateCount -=
|
||||
deleteOwnerCount; // guard this because in the "impossible"
|
||||
// event it is already 0 we'll wrap back to
|
||||
// int_max
|
||||
}
|
||||
// if removing this state entry would destroy the allotment then reduce
|
||||
// the owner count
|
||||
if (computeHookStateOwnerCount(stateCount) < oldStateReserve)
|
||||
adjustOwnerCount(view, sleAccount, -1, j);
|
||||
if (newHookStateCount < oldHookStateCount)
|
||||
adjustOwnerCount(view, sleAccount, -deleteOwnerCount, j);
|
||||
|
||||
sleAccount->setFieldU32(sfHookStateCount, stateCount);
|
||||
sleAccount->setFieldU32(sfHookStateCount, newHookStateCount);
|
||||
|
||||
if (nsDestroyed)
|
||||
hook::removeHookNamespaceEntry(*sleAccount, ns);
|
||||
@@ -1116,30 +1128,54 @@ hook::setHookState(
|
||||
|
||||
if (createNew)
|
||||
{
|
||||
++stateCount;
|
||||
uint32_t createdOwnerCount = computeHookStateOwnerCount(data);
|
||||
newHookStateCount += createdOwnerCount;
|
||||
|
||||
if (computeHookStateOwnerCount(stateCount) > oldStateReserve)
|
||||
if (newHookStateCount > oldHookStateCount)
|
||||
{
|
||||
// the hook used its allocated allotment of state entries for its
|
||||
// previous ownercount increment ownercount and give it another
|
||||
// allotment
|
||||
|
||||
++ownerCount;
|
||||
ownerCount += createdOwnerCount;
|
||||
XRPAmount const newReserve{view.fees().accountReserve(ownerCount)};
|
||||
|
||||
if (STAmount((*sleAccount)[sfBalance]).xrp() < newReserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
|
||||
adjustOwnerCount(view, sleAccount, 1, j);
|
||||
adjustOwnerCount(view, sleAccount, createdOwnerCount, j);
|
||||
}
|
||||
|
||||
// update state count
|
||||
sleAccount->setFieldU32(sfHookStateCount, stateCount);
|
||||
sleAccount->setFieldU32(sfHookStateCount, newHookStateCount);
|
||||
view.update(sleAccount);
|
||||
|
||||
// create an entry
|
||||
hookState = std::make_shared<SLE>(hookStateKeylet);
|
||||
}
|
||||
else
|
||||
{
|
||||
// on Update
|
||||
uint32_t oldOwnerCount =
|
||||
computeHookStateOwnerCount((*hookState)[sfHookStateData]);
|
||||
uint32_t newOwnerCount = computeHookStateOwnerCount(data);
|
||||
|
||||
uint32_t changedOwnerCount = newOwnerCount - oldOwnerCount;
|
||||
newHookStateCount += changedOwnerCount;
|
||||
|
||||
if (changedOwnerCount != 0)
|
||||
{
|
||||
ownerCount += changedOwnerCount;
|
||||
XRPAmount const newReserve{view.fees().accountReserve(ownerCount)};
|
||||
if (STAmount((*sleAccount)[sfBalance]).xrp() < newReserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
|
||||
adjustOwnerCount(view, sleAccount, changedOwnerCount, j);
|
||||
|
||||
sleAccount->setFieldU32(sfHookStateCount, newHookStateCount);
|
||||
view.update(sleAccount);
|
||||
}
|
||||
}
|
||||
|
||||
hookState->setFieldVL(sfHookStateData, data);
|
||||
hookState->setFieldH256(sfHookStateKey, key);
|
||||
@@ -1634,7 +1670,7 @@ DEFINE_HOOK_FUNCTION(
|
||||
(aread_len && NOT_IN_BOUNDS(aread_ptr, aread_len, memory_length)))
|
||||
return OUT_OF_BOUNDS;
|
||||
|
||||
uint32_t maxSize = hook::maxHookStateDataSize();
|
||||
uint32_t maxSize = hook::maxHookStateDataSize(view.rules());
|
||||
if (read_len > maxSize)
|
||||
return TOO_BIG;
|
||||
|
||||
|
||||
@@ -877,6 +877,7 @@ SetHook::destroyNamespace(
|
||||
|
||||
} while (cdirNext(view, dirKeylet.key, sleDirNode, uDirEntry, dirEntry));
|
||||
|
||||
uint32_t toDeleteOwnerCount = 0;
|
||||
// delete it!
|
||||
for (auto const& itemKey : toDelete)
|
||||
{
|
||||
@@ -892,6 +893,9 @@ SetHook::destroyNamespace(
|
||||
continue;
|
||||
}
|
||||
|
||||
toDeleteOwnerCount +=
|
||||
hook::computeHookStateOwnerCount((*sleItem)[sfHookStateData]);
|
||||
|
||||
auto const hint = (*sleItem)[sfOwnerNode];
|
||||
if (!view.dirRemove(dirKeylet, hint, itemKey, false))
|
||||
{
|
||||
@@ -905,7 +909,7 @@ SetHook::destroyNamespace(
|
||||
view.erase(sleItem);
|
||||
}
|
||||
|
||||
uint32_t stateCount = oldStateCount - toDelete.size();
|
||||
uint32_t stateCount = oldStateCount - toDeleteOwnerCount;
|
||||
if (stateCount > oldStateCount)
|
||||
{
|
||||
JLOG(ctx.j.fatal()) << "HookSet(" << hook::log::NSDELETE_COUNT << ")["
|
||||
@@ -921,7 +925,7 @@ SetHook::destroyNamespace(
|
||||
sleAccount->setFieldU32(sfHookStateCount, stateCount);
|
||||
|
||||
if (ctx.rules.enabled(fixNSDelete))
|
||||
adjustOwnerCount(view, sleAccount, -toDelete.size(), ctx.j);
|
||||
adjustOwnerCount(view, sleAccount, -toDeleteOwnerCount, ctx.j);
|
||||
|
||||
if (!partialDelete && sleAccount->isFieldPresent(sfHookNamespaces))
|
||||
hook::removeHookNamespaceEntry(*sleAccount, ns);
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace detail {
|
||||
// Feature.cpp. Because it's only used to reserve storage, and determine how
|
||||
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
|
||||
// the actual number of amendments. A LogicError on startup will verify this.
|
||||
static constexpr std::size_t numFeatures = 75;
|
||||
static constexpr std::size_t numFeatures = 76;
|
||||
|
||||
/** Amendments that this server supports and the default voting behavior.
|
||||
Whether they are enabled depends on the Rules defined in the validated
|
||||
@@ -363,7 +363,7 @@ extern uint256 const fixPageCap;
|
||||
extern uint256 const fix240911;
|
||||
extern uint256 const fixFloatDivide;
|
||||
extern uint256 const fixReduceImport;
|
||||
|
||||
extern uint256 const featureExtendedHookState;
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -469,6 +469,7 @@ REGISTER_FIX (fixPageCap, Supported::yes, VoteBehavior::De
|
||||
REGISTER_FIX (fix240911, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FIX (fixFloatDivide, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FIX (fixReduceImport, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FEATURE(ExtendedHookState, Supported::yes, VoteBehavior::DefaultNo);
|
||||
|
||||
// The following amendments are obsolete, but must remain supported
|
||||
// because they could potentially get enabled.
|
||||
|
||||
Reference in New Issue
Block a user