cleanup sethook, begin adding hooks logcodes

This commit is contained in:
Richard Holland
2022-02-03 15:20:21 +00:00
parent 664c77489d
commit 6adb9ae6f7
5 changed files with 369 additions and 161 deletions

View File

@@ -15,11 +15,76 @@
#include <ripple/app/tx/applyHookMacro.h>
#include <wasmedge/wasmedge.h>
enum HookSetFlags : uint8_t
{
hsfOVERRIDE = (1U << 0U), // override or delete hook
hsfNSDELETE = (1U << 1U), // delete namespace
};
enum HookSetOperation : int8_t
{
hsoINVALID = -1,
hsoNOOP = 0,
hsoCREATE = 1,
hsoINSTALL = 2,
hsoDELETE = 3,
hsoNSDELETE = 4,
hsoUPDATE = 5
};
namespace hook
{
struct HookContext;
struct HookResult;
bool isEmittedTxn(ripple::STTx const& tx);
namespace log
{
/*
* Hook log-codes are not necessarily errors. Each type of Hook log line contains a code in
* round parens like so:
* HookSet(5)[rAcc...]: message
* The log-code gives an external tool an easy way to handle and report the status of a hook
* to end users and developers.
*/
enum hook_log_code : uint16_t
{
/* HookSet log-codes */
SHORT_HOOK = 0, // web assembly byte code ended abruptly
CALL_ILLEGAL = 1, // wasm tries to call a non-whitelisted function
GUARD_PARAMETERS = 2, // guard called but did not use constant expressions for params
CALL_INDIRECT = 3, // wasm used call indirect instruction which is disallowed
GUARD_MISSING = 4, // guard call missing at top of loop
MEMORY_GROW = 5, // memory.grow instruction is present but disallowed
BLOCK_ILLEGAL = 6, // a block end instruction moves execution below depth 0 {{}}`}` <= like this
INSTRUCTION_COUNT = 7, // worst case execution instruction count as computed by HookSet
INSTRUCTION_EXCESS = 8, // worst case execution instruction count was too large
PARAMETERS_ILLEGAL = 9, // HookParameters contained something other than a HookParameter
PARAMETERS_FIELD = 10, // HookParameters contained a HookParameter with an invalid key in it
PARAMETERS_NAME = 11, // HookParameters contained a HookParameter which lacked ParameterName field
HASH_OR_CODE = 12, // HookSet object can contain only one of CreateCode and HookHash
GRANTS_EMPTY = 13, // HookSet object contained an empty grants array (you should remove it)
GRANTS_EXCESS = 14, // HookSet object cotnained a grants array with too many grants
GRANTS_ILLEGAL = 15, // Hookset object contained grants array which contained a non Grant object
GRANTS_FIELD = 16, // HookSet object contained a grant without Authorize or HookHash
API_ILLEGAL = 17, // HookSet object contained HookApiVersion for existing HookDefinition
NAMESPACE_MISSING = 18, // HookSet object lacked HookNamespace
API_MISSING = 19, // HookSet object did not contain HookApiVersion but should have
API_INVALID = 20, // HookSet object contained HookApiVersion for unrecognised hook API
HOOKON_MISSING = 21, // HookSet object did not contain HookOn but should have
DELETE_FIELD = 22, //
OVERRIDE_MISSING = 23, // HookSet object was trying to update or delete a hook but lacked hsfOVERRIDE
FLAGS_INVALID = 24, // HookSet flags were invalid for specified operation
NSDELETE_FIELD = 25,
NSDELETE_FLAGS = 26
//RH UPTO
};
};
}
namespace hook_api

View File

@@ -73,7 +73,8 @@ parseLeb128(std::vector<unsigned char>& buf, int start_offset, int* end_offset)
if (i >= hook.size())\
{\
JLOG(ctx.j.trace())\
<< "HookSet[" << HS_ACC() << "]: Malformed transaction: Hook truncated or otherwise invalid\n";\
<< "HookSet(" << hook::log::SHORT_HOOK << ")[" << HS_ACC() << "]: "\
<< "Malformed transaction: Hook truncated or otherwise invalid\n";\
return {false, 0};\
}\
}
@@ -132,7 +133,7 @@ check_guard(
if (callee_idx > last_import_idx)
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC() << "]: GuardCheck "
<< "HookSet(" << hook::log::CALL_ILLEGAL << ")[" << HS_ACC() << "]: GuardCheck "
<< "Hook calls a function outside of the whitelisted imports "
<< "codesec: " << codesec << " hook byte offset: " << i;
return {false, 0};
@@ -147,7 +148,7 @@ check_guard(
if (stack.size() < 2)
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC() << "]: GuardCheck "
<< "HookSet(" << hook::log::GUARD_PARAMETERS << ")[" << HS_ACC() << "]: GuardCheck "
<< "_g() called but could not detect constant parameters "
<< "codesec: " << codesec << " hook byte offset: " << i << "\n";
return {false, 0};
@@ -164,7 +165,8 @@ check_guard(
{
// 0 has a special meaning, generally it's not a constant value
// < 0 is a constant but negative, either way this is a reject condition
JLOG(ctx.j.trace()) << "HookSet[" << HS_ACC() << "]: GuardCheck "
JLOG(ctx.j.trace()) << "HookSet(" << hook::log::GUARD_PARAMETERS << ")"
<< "[" << HS_ACC() << "]: GuardCheck "
<< "_g() called but could not detect constant parameters "
<< "codesec: " << codesec << " hook byte offset: " << i << "\n";
return {false, 0};
@@ -177,7 +179,7 @@ check_guard(
if (DEBUG_GUARD_CHECK)
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC() << "]: GuardCheck "
<< "HookDebug[" << HS_ACC() << "]: GuardCheck "
<< "Depth " << block_depth << " guard: " << a;
}
}
@@ -195,7 +197,7 @@ check_guard(
if (instr == 0x11) // call indirect [ we don't allow guard to be called this way ]
{
JLOG(ctx.j.trace()) << "HookSet[" << HS_ACC() << "]: GuardCheck "
JLOG(ctx.j.trace()) << "HookSet(" << hook::log::CALL_INDIRECT << ")[" << HS_ACC() << "]: GuardCheck "
<< "Call indirect detected and is disallowed in hooks "
<< "codesec: " << codesec << " hook byte offset: " << i;
return {false, 0};
@@ -221,7 +223,8 @@ check_guard(
{
if (mode == 0)
{
JLOG(ctx.j.trace()) << "HookSet[" << HS_ACC() << "]: GuardCheck "
JLOG(ctx.j.trace()) << "HookSet(" << hook::log::GUARD_MISSING << ")"
<< "[" << HS_ACC() << "]: GuardCheck "
<< "_g() did not occur at start of function or loop statement "
<< "codesec: " << codesec << " hook byte offset: " << i;
return {false, 0};
@@ -365,7 +368,7 @@ check_guard(
if (instr == 0x40) // disallow memory.grow
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC() << "]: GuardCheck "
<< "HookSet(" << hook::log::MEMORY_GROW << ")[" << HS_ACC() << "]: GuardCheck "
<< "Memory.grow instruction not allowed at "
<< "codesec: " << codesec << " hook byte offset: " << i << "\n";
return {false, 0};
@@ -435,7 +438,7 @@ check_guard(
if (block_depth < 0)
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC() << "]: GuardCheck "
<< "HookSet(" << hook::log::BLOCK_ILLEGAL << ")[" << HS_ACC() << "]: GuardCheck "
<< "Unexpected 0x0B instruction, malformed"
<< "codesec: " << codesec << " hook byte offset: " << i;
return {false, 0};
@@ -449,14 +452,14 @@ check_guard(
}
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC() << "]: GuardCheck "
<< "HookSet(" << hook::log::INSTRUCTION_COUNT << ")[" << HS_ACC() << "]: GuardCheck "
<< "Total worse-case execution count: " << instruction_count[0].second;
// RH TODO: don't hardcode this
if (instruction_count[0].second > 0xFFFFF)
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC() << "]: GuardCheck "
<< "HookSet(" << hook::log::INSTRUCTION_EXCESS << ")[" << HS_ACC() << "]: GuardCheck "
<< "Maximum possible instructions exceed 1048575, please make your hook smaller "
<< "or check your guards!";
return {false, 0};
@@ -467,13 +470,56 @@ check_guard(
return {true, instruction_count[0].second};
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC() << "]: GuardCheck "
<< "HookSet(" << hook::log::GUARD_MISSING << ")[" << HS_ACC() << "]: GuardCheck "
<< "Guard did not occur before end of loop / function. "
<< "Codesec: " << codesec;
return {false, 0};
}
bool
validateHookGrants(SetHookCtx& ctx, STArray const& hookGrants)
{
if (hookGrants.size() < 1)
{
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::GRANTS_EMPTY << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook sfHookGrants empty.";
return false;
}
if (hookGrants.size() > 8)
{
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::GRANTS_EXCESS << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook sfHookGrants contains more than 8 entries.";
return false;
}
for (auto const& hookGrant : hookGrants)
{
auto const& hookGrantObj = dynamic_cast<STObject const*>(&hookGrant);
if (!hookGrantObj || (hookGrantObj->getFName() != sfHookGrant))
{
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::GRANTS_ILLEGAL << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook sfHookGrants did not contain sfHookGrant object.";
return false;
}
else if (!hookGrantObj->isFieldPresent(sfAuthorize) && !hookGrantObj->isFieldPresent(sfHookHash))
{
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::GRANTS_FIELD << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook sfHookGrant object did not contain either sfAuthorize "
<< "or sfHookHash.";
return false;
}
}
return true;
}
bool
validateHookParams(SetHookCtx& ctx, STArray const& hookParams)
{
@@ -484,7 +530,7 @@ validateHookParams(SetHookCtx& ctx, STArray const& hookParams)
if (!hookParamObj || (hookParamObj->getFName() != sfHookParameter))
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "HookSet(" << hook::log::PARAMETERS_ILLEGAL << ")[" << HS_ACC()
<< "]: Malformed transaction: "
<< "SetHook sfHookParameters contains obj other than sfHookParameter.";
return false;
@@ -498,7 +544,7 @@ validateHookParams(SetHookCtx& ctx, STArray const& hookParams)
if (name != sfHookParameterName && name != sfHookParameterValue)
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "HookSet(" << hook::log::PARAMETERS_FIELD << ")[" << HS_ACC()
<< "]: Malformed transaction: "
<< "SetHook sfHookParameter contains object other than sfHookParameterName/Value.";
return false;
@@ -511,7 +557,7 @@ validateHookParams(SetHookCtx& ctx, STArray const& hookParams)
if (!nameFound)
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "HookSet(" << hook::log::PARAMETERS_NAME << ")[" << HS_ACC()
<< "]: Malformed transaction: "
<< "SetHook sfHookParameter must contain at least sfHookParameterName";
return false;
@@ -521,140 +567,46 @@ validateHookParams(SetHookCtx& ctx, STArray const& hookParams)
return true;
}
// returns < valid, instruction count >
std::pair<bool, uint64_t>
validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
// infer which operation the user is attempting to execute from the present and absent fields
HookSetOperation inferOperation(STObject const& hookSetObj)
{
uint64_t maxInstrCount = 0;
uint64_t byteCount = 0;
uint64_t wasmByteCount = hookSetObj.isFieldPresent(sfCreateCode) ?
hookSetObj.getFieldVL(sfCreateCode).size() : 0;
bool hasHash = hookSetObj.isFieldPresent(sfHookHash);
bool hasCode = hookSetObj.isFieldPresent(sfCreateCode);
// mutex options: either link an existing hook or create a new one
if (hasHash && hasCode)
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "]: Malformed transaction: SetHook must provide only one of sfCreateCode or sfHookHash.";
return {false, 0};
}
// validate hook params structure
if (hookSetObj.isFieldPresent(sfHookParameters) &&
!validateHookParams(ctx, hookSetObj.getFieldArray(sfHookParameters)))
return {false, 0};
if (hasHash && hasCode) // Both HookHash and CreateCode: invalid
return hsoINVALID;
else if (hasHash) // Hookhash only: install
return hsoINSTALL;
else if (hasCode) // CreateCode only: either delete or create
return wasmByteCount > 0 ? hsoCREATE : hsoDELETE;
else if (
!hasHash && !hasCode &&
!hookSetObj.isFieldPresent(sfHookGrants) &&
!hookSetObj.isFieldPresent(sfHookNamespace) &&
!hookSetObj.isFieldPresent(sfHookParameters) &&
!hookSetObj.isFieldPresent(sfHookOn) &&
!hookSetObj.isFieldPresent(sfHookApiVersion) &&
!hookSetObj.isFieldPresent(sfFlags))
return hsoNOOP;
return hookSetObj.isFieldPresent(sfHookNamespace) ? hsoNSDELETE : hsoUPDATE;
// validate hook grants structure
if (hookSetObj.isFieldPresent(sfHookGrants))
{
auto const& hookGrants = hookSetObj.getFieldArray(sfHookGrants);
if (hookGrants.size() < 1)
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "]: Malformed transaction: SetHook sfHookGrants empty.";
return {false, 0};
}
if (hookGrants.size() > 8)
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "]: Malformed transaction: SetHook sfHookGrants contains more than 8 entries.";
return {false, 0};
}
for (auto const& hookGrant : hookGrants)
{
auto const& hookGrantObj = dynamic_cast<STObject const*>(&hookGrant);
if (!hookGrantObj || (hookGrantObj->getFName() != sfHookGrant))
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "]: Malformed transaction: SetHook sfHookGrants did not contain sfHookGrant object.";
return {false, 0};
}
else if (!hookGrantObj->isFieldPresent(sfAuthorize) && !hookGrantObj->isFieldPresent(sfHookHash))
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "]: Malformed transaction: SetHook sfHookGrant object did not contain either sfAuthorize "
<< "or sfHookHash.";
return {false, 0};
}
}
}
// link existing hook
if (hasHash)
{
// ensure no hookapiversion field was provided
if (hookSetObj.isFieldPresent(sfHookApiVersion))
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "]: Malformed transaction: HookApiVersion can only be provided when creating a new hook.";
return {false, 0};
}
return {true, 0};
}
// execution to here means this is an sfCreateCode (hook creation) entry
// ensure hooknamespace is present
if (!hookSetObj.isFieldPresent(sfHookNamespace))
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "]: Malformed transaction: SetHook sfHookDefinition must contain sfHookNamespace.";
return {false, 0};
}
// validate api version, if provided
if (!hookSetObj.isFieldPresent(sfHookApiVersion))
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "]: Malformed transaction: SetHook sfHookApiVersion must be included.";
return {false, 0};
}
else
{
auto version = hookSetObj.getFieldU16(sfHookApiVersion);
if (version != 0)
{
// we currently only accept api version 0
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "]: Malformed transaction: SetHook sfHookDefinition->sfHookApiVersion invalid. (Try 0).";
return {false, 0};
}
}
// validate sfHookOn
if (!hookSetObj.isFieldPresent(sfHookOn))
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "]: Malformed transaction: SetHook must include sfHookOn when creating a new hook.";
return {false, 0};
}
}
// validate createcode
std::pair<bool, uint64_t>
validateCreateCode(SetHookCtx& ctx, STObject const& hookSetObj)
{
if (!hookSetObj.isFieldPresent(sfCreateCode))
return { false, 0 };
uint64_t maxInstrCount = 0;
Blob hook = hookSetObj.getFieldVL(sfCreateCode);
if (hook.empty())
{
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "]: Malformed transaction: SetHook sfHookDefinition must contain non-blank sfCreateCode.";
return {false, 0};
}
byteCount = hook.size();
uint64_t byteCount = hook.size();
// RH TODO compute actual smallest possible hook and update this value
if (byteCount < 10)
@@ -934,6 +886,205 @@ validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
return {true, maxInstrCount};
}
// returns < valid, instruction count >
std::pair<bool, uint64_t>
validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
{
uint32_t flags = hookSetObj.isFieldPresent(sfFlags) ? hookSetObj.getFieldU32(sfFlags) : 0;
switch (inferOperation(hookSetObj))
{
case hsoNOOP:
{
return {true, 0};
}
case hsoNSDELETE:
{
// namespace delete operation
if (hookSetObj.isFieldPresent(sfHookGrants) ||
hookSetObj.isFieldPresent(sfHookParameters) ||
hookSetObj.isFieldPresent(sfHookOn) ||
hookSetObj.isFieldPresent(sfHookApiVersion) ||
!hookSetObj.isFieldPresent(sfFlags) ||
!hookSetObj.isFieldPresent(sfHookNamespace))
{
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::NSDELETE_FIELD << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook nsdelete operation should contain only "
<< "sfHookNamespace & sfFlags";
return {false, 0};
}
if (flags != hsfNSDELETE)
{
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::NSDELETE_FLAGS << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook nsdelete operation should only specify hsfNSDELETE";
return {false, 0};
}
return {true, 0};
}
case hsoDELETE:
{
if (hookSetObj.isFieldPresent(sfHookGrants) ||
hookSetObj.isFieldPresent(sfHookParameters) ||
hookSetObj.isFieldPresent(sfHookOn) ||
hookSetObj.isFieldPresent(sfHookApiVersion) ||
hookSetObj.isFieldPresent(sfHookNamespace) ||
!hookSetObj.isFieldPresent(sfFlags))
{
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::DELETE_FIELD << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook delete operation should contain only sfCreateCode & sfFlags";
return {false, 0};
}
if (!(flags & hsfOVERRIDE))
{
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::OVERRIDE_MISSING << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook delete operation was missing the hsfOVERRIDE flag";
return {false, 0};
}
if (flags & ~(hsfOVERRIDE | hsfNSDELETE))
{
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::FLAGS_INVALID << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook delete operation specified invalid flags";
return {false, 0};
}
return {true, 0};
}
case hsoINSTALL:
{
// validate hook params structure, if any
if (hookSetObj.isFieldPresent(sfHookParameters) &&
!validateHookParams(ctx, hookSetObj.getFieldArray(sfHookParameters)))
return {false, 0};
// validate hook grants structure, if any
if (hookSetObj.isFieldPresent(sfHookGrants) &&
!validateHookGrants(ctx, hookSetObj.getFieldArray(sfHookGrants)))
return {false, 0};
// api version not allowed in update
if (hookSetObj.isFieldPresent(sfHookApiVersion))
{
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::API_ILLEGAL << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook install operation sfHookApiVersion must not be included.";
return {false, 0};
}
// namespace may be valid, if the user so chooses
// hookon may be present if the user so chooses
// flags may be present if the user so chooses
return {true, 0};
}
case hsoUPDATE:
{
// validate hook params structure
if (hookSetObj.isFieldPresent(sfHookParameters) &&
!validateHookParams(ctx, hookSetObj.getFieldArray(sfHookParameters)))
return {false, 0};
// validate hook grants structure
if (hookSetObj.isFieldPresent(sfHookGrants) &&
!validateHookGrants(ctx, hookSetObj.getFieldArray(sfHookGrants)))
return {false, 0};
// api version not allowed in update
if (hookSetObj.isFieldPresent(sfHookApiVersion))
{
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::API_ILLEGAL << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook update operation sfHookApiVersion must not be included.";
return {false, 0};
}
// namespace may be valid, if the user so chooses
// hookon may be present if the user so chooses
// flags may be present if the user so chooses
return {true, 0};
}
case hsoCREATE:
{
// validate hook params structure
if (hookSetObj.isFieldPresent(sfHookParameters) &&
!validateHookParams(ctx, hookSetObj.getFieldArray(sfHookParameters)))
return {false, 0};
// validate hook grants structure
if (hookSetObj.isFieldPresent(sfHookGrants) &&
!validateHookGrants(ctx, hookSetObj.getFieldArray(sfHookGrants)))
return {false, 0};
// ensure hooknamespace is present
if (!hookSetObj.isFieldPresent(sfHookNamespace))
{
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::NAMESPACE_MISSING << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook sfHookDefinition must contain sfHookNamespace.";
return {false, 0};
}
// validate api version, if provided
if (!hookSetObj.isFieldPresent(sfHookApiVersion))
{
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::API_MISSING << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook sfHookApiVersion must be included.";
return {false, 0};
}
auto version = hookSetObj.getFieldU16(sfHookApiVersion);
if (version != 0)
{
// we currently only accept api version 0
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::API_INVALID << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook sfHook->sfHookApiVersion invalid. (Try 0).";
return {false, 0};
}
// validate sfHookOn
if (!hookSetObj.isFieldPresent(sfHookOn))
{
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::HOOKON_MISSING << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook must include sfHookOn when creating a new hook.";
return {false, 0};
}
// finally validate web assembly byte code
return validateCreateCode(ctx, hookSetObj);
}
case hsoINVALID:
default:
{
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::HASH_OR_CODE << ")[" << HS_ACC()
<< "]: Malformed transaction: SetHook must provide only one of sfCreateCode or sfHookHash.";
return {false, 0};
}
}
}
FeeUnit64
SetHook::calculateBaseFee(ReadView const& view, STTx const& tx)
{
@@ -1201,7 +1352,7 @@ SetHook::destroyNamespace(
oldDirSLE->setFieldU64(sfReferenceCount, refCount);\
view().update(oldDirSLE);\
if (refCount <= 0)\
dirsToDestroy[oldDirKeylet->key] = flags & FLAG_NSDELETE;\
dirsToDestroy[oldDirKeylet->key] = flags & hsfNSDELETE;\
}
#define DIRECTORY_INC()\
@@ -1248,7 +1399,7 @@ SetHook::destroyNamespace(
oldDefSLE->setFieldU64(sfReferenceCount, refCount-1);\
view().update(oldDefSLE);\
if (refCount <= 0)\
defsToDestroy[oldDefKeylet->key] = flags & FLAG_OVERRIDE;\
defsToDestroy[oldDefKeylet->key] = flags & hsfOVERRIDE;\
}
#define DEFINITION_INC()\
@@ -1361,7 +1512,6 @@ SetHook::setHook()
bool isDeleteOperation =
hasCreateCode && hookSetObj->getFieldVL(sfCreateCode).size() == 0;
printf("PATH X\n");
bool isUpdateOperation =
oldHook && hasHookHash &&
(hookSetObj->getFieldH256(sfHookHash) == oldHook->get().getFieldH256(sfHookHash));
@@ -1388,7 +1538,7 @@ SetHook::setHook()
if (oldHook)
{
// certain actions require explicit flagging to prevent user error
if (!(flags & FLAG_OVERRIDE) && !isUpdateOperation)
if (!(flags & hsfOVERRIDE) && !isUpdateOperation)
{
// deletes (and creates that override an existing hook) require a flag
JLOG(ctx.j.trace())
@@ -1783,7 +1933,7 @@ SetHook::setHook()
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "]: Malformed transaction: SetHook operation would delete a namespace of hook states"
<< " but to do this you must set the NSDELETE flag";
<< " but to do this you must set the hsfNSDELETE flag";
return tecREQUIRES_FLAG;
}
@@ -1805,7 +1955,7 @@ SetHook::setHook()
JLOG(ctx.j.trace())
<< "HookSet[" << HS_ACC()
<< "]: Malformed transaction: SetHook operation would delete a hook"
<< " but to do this you must set the OVERRIDE flag";
<< " but to do this you must set the hsfOVERRIDE flag";
return tecREQUIRES_FLAG;
}
view().erase(sle);

View File

@@ -33,15 +33,11 @@
#include <algorithm>
#include <cstdint>
#include <vector>
#include <ripple/app/tx/applyHook.h>
namespace ripple {
enum SetHookFlags : uint8_t {
FLAG_OVERRIDE = 1U,
FLAG_NSDELETE = 2U
};
struct SetHookCtx
{
beast::Journal j;

View File

@@ -59,15 +59,12 @@ static SField::private_access_tag_t access;
#pragma push_macro("CONSTRUCT_TYPED_SFIELD")
#undef CONSTRUCT_TYPED_SFIELD
#define XSTR(x) STR(x)
#define STR(x) #x
#define CONSTRUCT_TYPED_SFIELD(sfName, txtName, stiSuffix, fieldValue, ...) \
SF_##stiSuffix const sfName( \
access, STI_##stiSuffix, fieldValue, txtName, ##__VA_ARGS__); \
static_assert( \
std::string_view(#sfName) == "sf" txtName, \
"Declaration of SField does not match its text name: " txtName)
"Declaration of SField does not match its text name")
// clang-format off
@@ -100,11 +97,11 @@ CONSTRUCT_TYPED_SFIELD(sfSignerWeight, "SignerWeight", UINT16,
CONSTRUCT_TYPED_SFIELD(sfTransferFee, "TransferFee", UINT16, 4);
// 16-bit integers (uncommon)
CONSTRUCT_TYPED_SFIELD(sfVersion, "Version", UINT16, 16);
CONSTRUCT_TYPED_SFIELD(sfHookStateChangeCount, "HookStateChangeCount", UINT16, 17);
CONSTRUCT_TYPED_SFIELD(sfHookEmitCount, "HookEmitCount", UINT16, 18);
CONSTRUCT_TYPED_SFIELD(sfHookExecutionIndex, "HookExecutionIndex", UINT16, 19);
CONSTRUCT_TYPED_SFIELD(sfHookApiVersion, "HookApiVersion", UINT16, 20);
CONSTRUCT_TYPED_SFIELD(sfVersion, "Version", UINT16, 16);
CONSTRUCT_TYPED_SFIELD(sfHookStateChangeCount, "HookStateChangeCount", UINT16, 17);
CONSTRUCT_TYPED_SFIELD(sfHookEmitCount, "HookEmitCount", UINT16, 18);
CONSTRUCT_TYPED_SFIELD(sfHookExecutionIndex, "HookExecutionIndex", UINT16, 19);
CONSTRUCT_TYPED_SFIELD(sfHookApiVersion, "HookApiVersion", UINT16, 20);
// 32-bit integers (common)
CONSTRUCT_TYPED_SFIELD(sfFlags, "Flags", UINT32, 2);

View File

@@ -2385,12 +2385,12 @@ public:
std::shared_ptr<Transaction>&,
bool,
bool,
bool,
NetworkOPs::FailHard)
{
;
}
void
testTransactionRPC()
{