Compare commits

..

7 Commits

Author SHA1 Message Date
Richard Holland
87bbf5efc0 add additional expects to ensure map carry-over in test suit 2026-06-16 16:30:20 +10:00
Richard Holland
888d35b8dc Merge branch 'dev' into fixhookmap 2026-06-16 15:31:32 +10:00
Richard Holland
7a0059ae80 Merge branch 'dev' into fixhookmap 2026-06-16 13:57:42 +10:00
Richard Holland
d58cddf554 test cases for hookmap fix 2026-06-12 16:20:47 +10:00
Richard Holland
632df895d4 use pair for consistency 2026-06-05 15:59:57 +10:00
Richard Holland
e9a2e71124 add namespaces to the grants cache 2026-06-05 15:43:38 +10:00
Richard Holland
1b6da60399 initial version of hookmap fix, compiling but needs tests 2026-06-05 11:37:18 +10:00
8 changed files with 38 additions and 102 deletions

View File

@@ -95,16 +95,8 @@ if [[ "$4" == "" ]]; then
echo "Non GH, local building, no Action runner magic"
else
# GH Action, runner
if [[ "$(git rev-parse --abbrev-ref HEAD)" == "release" ]]; then
echo "building on the release branch... placing it in builds/candidate"
mkdir /data/builds/candidate
cp /io/release-build/xahaud /data/builds/candidate/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
cp /io/release-build/release.info /data/builds/candidate/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4.releaseinfo
else
echo "building non-release branch, placing it in builds root"
cp /io/release-build/xahaud /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
cp /io/release-build/release.info /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4.releaseinfo
fi
cp /io/release-build/xahaud /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
cp /io/release-build/release.info /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4.releaseinfo
echo "Published build to: http://build.xahau.tech/"
echo $(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
fi

View File

@@ -34,7 +34,6 @@
// If you add an amendment here, then do not forget to increment `numFeatures`
// in include/xrpl/protocol/Feature.h.
XRPL_FIX (HookNameValidation, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (HookMap, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (GuardDepth32, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(NamedHooks, Supported::yes, VoteBehavior::DefaultNo)

View File

@@ -563,20 +563,6 @@ public:
env(reward::claim(alice),
reward::issuer(issuer),
ter(tecNO_TARGET));
env.close();
}
// Invalid HookName
{
auto hookObj = hso(jtx::genesis::AcceptHook, overrideFlag);
hookObj[jss::HookOn] = to_string(~UINT256_BIT[ttCLAIM_REWARD]);
hookObj[jss::HookName] = "4142434445";
env(hook(issuer, {{hookObj}}, 0), fee(XRP(1)));
env.close();
env(reward::claim(alice),
reward::issuer(issuer),
ter(tecNO_TARGET));
env.close();
}
// Vaild HookOn
{

View File

@@ -2002,35 +2002,11 @@ public:
BEAST_EXPECT(!env.meta()->isFieldPresent(sfHookEmissions));
}
// Call named hook with the wrong hook name (size == 0)
for (auto const fix : {true, false})
{
auto f = features - fixHookNameValidation;
if (fix)
f = f | fixHookNameValidation;
Env env{*this, f};
env.fund(XRP(10000), alice);
// execute both named and non-named hooks
auto jv = invoke::invoke(alice);
jv[jss::HookName] = "";
auto const expected = fix ? ter(temMALFORMED) : ter(tesSUCCESS);
env(jv,
M("Call named hook with the wrong hook name (size == 0)"),
HSFEE,
ter(expected));
env.close();
}
// Call named hook with the wrong hook name (size > 0)
// Call named hook with the wrong hook name
{
auto jv = invoke::invoke(alice);
jv[jss::HookName] = "41424345";
env(jv,
M("Call named hook with the wrong hook name (size > 0)"),
HSFEE);
env(jv, M("Call named hook with the wrong hook name"), HSFEE);
env.close();
// execute only non-named hook
BEAST_EXPECT(!env.meta()->isFieldPresent(sfHookEmissions));

View File

@@ -82,13 +82,10 @@ namespace hook_api {
namespace hook {
bool
canHook(
STTx const& tx,
ripple::uint256 const& hookOn,
std::optional<ripple::Blob> const& hookName);
canHook(ripple::TxType txType, ripple::uint256 hookOn);
bool
canEmit(ripple::TxType const& txType, ripple::uint256 const& hookCanEmit);
canEmit(ripple::TxType txType, ripple::uint256 hookCanEmit);
ripple::uint256
getHookCanEmit(ripple::STObject const& hookObj, SLE::pointer const& hookDef);

View File

@@ -813,44 +813,21 @@ hook::removeHookNamespaceEntry(ripple::SLE& sleAccount, ripple::uint256 ns)
// transactions. If you wish to set a hook that has control over ttHOOK_SET then
// set bit 1U<<22.
bool
canHookTT(ripple::TxType const& txType, ripple::uint256 const& hookOn)
hook::canHook(ripple::TxType txType, ripple::uint256 hookOn)
{
uint256 hookOnCopy = hookOn;
// invert ttHOOK_SET bit
hookOnCopy ^= UINT256_BIT[ttHOOK_SET];
hookOn ^= UINT256_BIT[ttHOOK_SET];
// invert entire field
hookOnCopy = ~hookOnCopy;
hookOn = ~hookOn;
return (hookOnCopy & UINT256_BIT[txType]) != beast::zero;
return (hookOn & UINT256_BIT[txType]) != beast::zero;
}
bool
hook::canEmit(ripple::TxType const& txType, ripple::uint256 const& hookCanEmit)
hook::canEmit(ripple::TxType txType, ripple::uint256 hookCanEmit)
{
return canHookTT(txType, hookCanEmit);
}
bool
hook::canHook(
STTx const& tx,
ripple::uint256 const& hookOn,
std::optional<ripple::Blob> const& hookName)
{
if (!canHookTT(tx.getTxnType(), hookOn))
return false;
if (!hookName)
// no hook name specified to hook, so we can always hook
return true;
if (!tx.isFieldPresent(sfHookName))
// hook name specified hook, but no hook name specified in the
// transaction, so we can't hook without the hook name
return false;
return tx.getFieldVL(sfHookName) == hookName;
return hook::canHook(txType, hookCanEmit);
}
ripple::uint256

View File

@@ -164,12 +164,7 @@ ClaimReward::preclaim(PreclaimContext const& ctx)
auto const& hookOn =
hook::getHookOn(hook, sleDef, sfHookOnIncoming);
auto const& hookName =
ctx.view.rules().enabled(fixHookNameValidation) &&
hook.isFieldPresent(sfHookName)
? std::optional<ripple::Blob>(hook.getFieldVL(sfHookName))
: std::nullopt;
if (hook::canHook(ctx.tx, hookOn, hookName))
if (hook::canHook(ttCLAIM_REWARD, hookOn))
{
hasClaimRewardHook = true;
break;

View File

@@ -155,11 +155,7 @@ preflight1(PreflightContext const& ctx)
!ctx.rules.enabled(featureNamedHooks))
return temMALFORMED;
auto const& name = ctx.tx.getFieldVL(sfHookName);
if (name.size() == 0 && ctx.rules.enabled(fixHookNameValidation))
return temMALFORMED;
if (!SetHook::validateHookName(name, ctx.j))
if (!SetHook::validateHookName(ctx.tx.getFieldVL(sfHookName), ctx.j))
return temMALFORMED;
}
@@ -287,10 +283,19 @@ Transactor::calculateHookChainFee(
// LCOV_EXCL_STOP
}
std::optional<Blob> hookName;
std::optional<Blob> requiredHookName;
if (hookObj.isFieldPresent(sfHookName) &&
hookObj.getFieldVL(sfHookName).size() > 0)
hookName = hookObj.getFieldVL(sfHookName);
requiredHookName = hookObj.getFieldVL(sfHookName);
if (requiredHookName)
{
// need to specify same hook name in the transaction
if (!tx.isFieldPresent(sfHookName))
continue;
if (*requiredHookName != tx.getFieldVL(sfHookName))
continue;
}
uint32_t flags = 0;
if (hookObj.isFieldPresent(sfFlags))
@@ -302,7 +307,7 @@ Transactor::calculateHookChainFee(
uint256 hookOn = hook::getHookOn(
hookObj, hookDef, isOutgoing ? sfHookOnOutgoing : sfHookOnIncoming);
if (hook::canHook(tx, hookOn, hookName) &&
if (hook::canHook(tx.getTxnType(), hookOn) &&
(!collectCallsOnly || (flags & hook::hsfCOLLECT)))
{
XRPAmount const toAdd{hookDef->getFieldAmount(sfFee).xrp().drops()};
@@ -1349,16 +1354,25 @@ Transactor::executeHookChain(
// LCOV_EXCL_STOP
}
std::optional<Blob> hookName;
std::optional<Blob> requiredHookName;
if (hookObj.isFieldPresent(sfHookName) &&
hookObj.getFieldVL(sfHookName).size() > 0)
hookName = hookObj.getFieldVL(sfHookName);
requiredHookName = hookObj.getFieldVL(sfHookName);
if (requiredHookName)
{
// need to specify same hook name in the transaction
if (!ctx_.tx.isFieldPresent(sfHookName))
continue;
if (*requiredHookName != ctx_.tx.getFieldVL(sfHookName))
continue;
}
// check if the hook can fire
uint256 hookOn = hook::getHookOn(
hookObj, hookDef, isOutgoing ? sfHookOnOutgoing : sfHookOnIncoming);
if (!hook::canHook(ctx_.tx, hookOn, hookName))
if (!hook::canHook(ctx_.tx.getTxnType(), hookOn))
continue; // skip if it can't
uint256 hookCanEmit = hook::getHookCanEmit(hookObj, hookDef);