Skip to content

Commit 67a6970

Browse files
authored
Outgoing/Incoming HookOn (#457)
1 parent efd5f9f commit 67a6970

File tree

14 files changed

+617
-49
lines changed

14 files changed

+617
-49
lines changed

hook/sfcodes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@
136136
#define sfEmittedTxnID ((5U << 16U) + 97U)
137137
#define sfHookCanEmit ((5U << 16U) + 96U)
138138
#define sfCron ((5U << 16U) + 95U)
139+
#define sfHookOnIncoming ((5U << 16U) + 94U)
140+
#define sfHookOnOutgoing ((5U << 16U) + 93U)
139141
#define sfAmount ((6U << 16U) + 1U)
140142
#define sfBalance ((6U << 16U) + 2U)
141143
#define sfLimitAmount ((6U << 16U) + 3U)

src/ripple/app/hook/applyHook.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ canEmit(ripple::TxType txType, ripple::uint256 hookCanEmit);
8989
ripple::uint256
9090
getHookCanEmit(ripple::STObject const& hookObj, SLE::pointer const& hookDef);
9191

92+
ripple::uint256
93+
getHookOn(
94+
STObject const& obj,
95+
std::shared_ptr<SLE const> const& def,
96+
SField const& field);
97+
9298
struct HookResult;
9399

94100
HookResult

src/ripple/app/hook/impl/applyHook.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,23 @@ hook::getHookCanEmit(
921921
return hookCanEmit;
922922
}
923923

924+
ripple::uint256
925+
hook::getHookOn(
926+
STObject const& obj,
927+
std::shared_ptr<SLE const> const& def,
928+
SField const& field)
929+
{
930+
if (obj.isFieldPresent(field))
931+
return obj.getFieldH256(field);
932+
if (obj.isFieldPresent(sfHookOn))
933+
return obj.getFieldH256(sfHookOn);
934+
if (def->isFieldPresent(field))
935+
return def->getFieldH256(field);
936+
if (def->isFieldPresent(sfHookOn))
937+
return def->getFieldH256(sfHookOn);
938+
return uint256{0};
939+
};
940+
924941
// Update HookState ledger objects for the hook... only called after accept()
925942
// assumes the specified acc has already been checked for authoriation (hook
926943
// grants)

src/ripple/app/tx/impl/SetHook.cpp

Lines changed: 156 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,9 @@ SetHook::inferOperation(STObject const& hookSetObj)
225225
!hasHash && !hasCode && !hookSetObj.isFieldPresent(sfHookGrants) &&
226226
!hookSetObj.isFieldPresent(sfHookNamespace) &&
227227
!hookSetObj.isFieldPresent(sfHookParameters) &&
228-
!hookSetObj.isFieldPresent(sfHookOn) &&
228+
!(hookSetObj.isFieldPresent(sfHookOn) ||
229+
(hookSetObj.isFieldPresent(sfHookOnOutgoing) &&
230+
hookSetObj.isFieldPresent(sfHookOnIncoming))) &&
229231
!hookSetObj.isFieldPresent(sfHookCanEmit) &&
230232
!hookSetObj.isFieldPresent(sfHookApiVersion) &&
231233
!hookSetObj.isFieldPresent(sfFlags))
@@ -261,6 +263,8 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
261263
if (hookSetObj.isFieldPresent(sfHookGrants) ||
262264
hookSetObj.isFieldPresent(sfHookParameters) ||
263265
hookSetObj.isFieldPresent(sfHookOn) ||
266+
hookSetObj.isFieldPresent(sfHookOnOutgoing) ||
267+
hookSetObj.isFieldPresent(sfHookOnIncoming) ||
264268
hookSetObj.isFieldPresent(sfHookCanEmit) ||
265269
hookSetObj.isFieldPresent(sfHookApiVersion) ||
266270
!hookSetObj.isFieldPresent(sfFlags) ||
@@ -291,6 +295,8 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
291295
if (hookSetObj.isFieldPresent(sfHookGrants) ||
292296
hookSetObj.isFieldPresent(sfHookParameters) ||
293297
hookSetObj.isFieldPresent(sfHookOn) ||
298+
hookSetObj.isFieldPresent(sfHookOnOutgoing) ||
299+
hookSetObj.isFieldPresent(sfHookOnIncoming) ||
294300
hookSetObj.isFieldPresent(sfHookCanEmit) ||
295301
hookSetObj.isFieldPresent(sfHookApiVersion) ||
296302
hookSetObj.isFieldPresent(sfHookNamespace) ||
@@ -448,12 +454,53 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
448454
// validate sfHookOn
449455
if (!hookSetObj.isFieldPresent(sfHookOn))
450456
{
451-
JLOG(ctx.j.trace())
452-
<< "HookSet(" << hook::log::HOOKON_MISSING << ")["
453-
<< HS_ACC()
454-
<< "]: Malformed transaction: SetHook must include "
455-
"sfHookOn when creating a new hook.";
456-
return false;
457+
if (!ctx.rules.enabled(featureHookOnV2))
458+
{
459+
JLOG(ctx.j.trace())
460+
<< "HookSet(" << hook::log::HOOKON_MISSING << ")["
461+
<< HS_ACC()
462+
<< "]: Malformed transaction: SetHook must include "
463+
"sfHookOn before featureHookOnV2 is enabled.";
464+
return false;
465+
}
466+
467+
if (!hookSetObj.isFieldPresent(sfHookOnOutgoing) ||
468+
!hookSetObj.isFieldPresent(sfHookOnIncoming))
469+
{
470+
JLOG(ctx.j.trace())
471+
<< "HookSet(" << hook::log::HOOKON_MISSING << ")["
472+
<< HS_ACC()
473+
<< "]: Malformed transaction: SetHook must include "
474+
"sfHookOnOutgoing and sfHookOnIncoming "
475+
"when creating a new hook without sfHookOn.";
476+
return false;
477+
}
478+
479+
auto const outgoing = hookSetObj.getFieldH256(sfHookOnOutgoing);
480+
auto const incoming = hookSetObj.getFieldH256(sfHookOnIncoming);
481+
if (outgoing == incoming)
482+
{
483+
JLOG(ctx.j.trace())
484+
<< "HookSet(" << hook::log::HOOKON_MISSING << ")["
485+
<< HS_ACC()
486+
<< "]: Malformed transaction: SetHook outgoing and "
487+
"incoming hookon must be different.";
488+
return false;
489+
}
490+
}
491+
else
492+
{
493+
if (hookSetObj.isFieldPresent(sfHookOnOutgoing) ||
494+
hookSetObj.isFieldPresent(sfHookOnIncoming))
495+
{
496+
JLOG(ctx.j.trace())
497+
<< "HookSet(" << hook::log::HOOKON_MISSING << ")["
498+
<< HS_ACC()
499+
<< "]: Malformed transaction: SetHook must no"
500+
"include sfHookOnOutgoing and sfHookOnIncoming "
501+
"when creating a new hook with sfHookOn.";
502+
return false;
503+
}
457504
}
458505

459506
// validate sfHookCanEmit
@@ -742,7 +789,8 @@ SetHook::preflight(PreflightContext const& ctx)
742789

743790
if (name != sfCreateCode && name != sfHookHash &&
744791
name != sfHookNamespace && name != sfHookParameters &&
745-
name != sfHookOn && name != sfHookGrants &&
792+
name != sfHookOn && name != sfHookOnOutgoing &&
793+
name != sfHookOnIncoming && name != sfHookGrants &&
746794
name != sfHookApiVersion && name != sfFlags &&
747795
name != sfHookCanEmit)
748796
{
@@ -1264,10 +1312,14 @@ SetHook::setHook()
12641312
std::optional<ripple::uint256> newNamespace;
12651313
std::optional<ripple::Keylet> newDirKeylet;
12661314

1267-
std::optional<uint256> oldHookOn;
12681315
std::optional<uint256> newHookOn;
12691316
std::optional<uint256> defHookOn;
12701317

1318+
std::optional<uint256> newHookOnOutgoing;
1319+
std::optional<uint256> newHookOnIncoming;
1320+
std::optional<uint256> defHookOnOutgoing;
1321+
std::optional<uint256> defHookOnIncoming;
1322+
12711323
std::optional<uint256> oldHookCanEmit;
12721324
std::optional<uint256> newHookCanEmit;
12731325
std::optional<uint256> defHookCanEmit;
@@ -1325,13 +1377,18 @@ SetHook::setHook()
13251377

13261378
oldDirKeylet = keylet::hookStateDir(account_, *oldNamespace);
13271379
oldDirSLE = view().peek(*oldDirKeylet);
1328-
if (oldDefSLE)
1380+
if (oldDefSLE && oldDefSLE->isFieldPresent(sfHookOn))
13291381
defHookOn = oldDefSLE->getFieldH256(sfHookOn);
13301382

1331-
if (oldHook->get().isFieldPresent(sfHookOn))
1332-
oldHookOn = oldHook->get().getFieldH256(sfHookOn);
1333-
else if (defHookOn)
1334-
oldHookOn = *defHookOn;
1383+
if (oldDefSLE)
1384+
{
1385+
if (oldDefSLE->isFieldPresent(sfHookOnOutgoing))
1386+
defHookOnOutgoing =
1387+
oldDefSLE->getFieldH256(sfHookOnOutgoing);
1388+
if (oldDefSLE->isFieldPresent(sfHookOnIncoming))
1389+
defHookOnIncoming =
1390+
oldDefSLE->getFieldH256(sfHookOnIncoming);
1391+
}
13351392

13361393
if (oldDefSLE && oldDefSLE->isFieldPresent(sfHookCanEmit))
13371394
defHookCanEmit = oldDefSLE->getFieldH256(sfHookCanEmit);
@@ -1356,6 +1413,14 @@ SetHook::setHook()
13561413
if (hookSetObj->get().isFieldPresent(sfHookOn))
13571414
newHookOn = hookSetObj->get().getFieldH256(sfHookOn);
13581415

1416+
if (hookSetObj->get().isFieldPresent(sfHookOnOutgoing))
1417+
newHookOnOutgoing =
1418+
hookSetObj->get().getFieldH256(sfHookOnOutgoing);
1419+
1420+
if (hookSetObj->get().isFieldPresent(sfHookOnIncoming))
1421+
newHookOnIncoming =
1422+
hookSetObj->get().getFieldH256(sfHookOnIncoming);
1423+
13591424
if (hookSetObj->get().isFieldPresent(sfHookCanEmit))
13601425
newHookCanEmit = hookSetObj->get().getFieldH256(sfHookCanEmit);
13611426

@@ -1469,6 +1534,14 @@ SetHook::setHook()
14691534
if (oldHook->get().isFieldPresent(sfHookOn))
14701535
newHook.setFieldH256(
14711536
sfHookOn, oldHook->get().getFieldH256(sfHookOn));
1537+
if (oldHook->get().isFieldPresent(sfHookOnOutgoing))
1538+
newHook.setFieldH256(
1539+
sfHookOnOutgoing,
1540+
oldHook->get().getFieldH256(sfHookOnOutgoing));
1541+
if (oldHook->get().isFieldPresent(sfHookOnIncoming))
1542+
newHook.setFieldH256(
1543+
sfHookOnIncoming,
1544+
oldHook->get().getFieldH256(sfHookOnIncoming));
14721545
if (oldHook->get().isFieldPresent(sfHookCanEmit))
14731546
newHook.setFieldH256(
14741547
sfHookCanEmit,
@@ -1502,6 +1575,24 @@ SetHook::setHook()
15021575
newHook.setFieldH256(sfHookOn, *newHookOn);
15031576
}
15041577

1578+
if (newHookOnOutgoing)
1579+
{
1580+
if (*defHookOnOutgoing == *newHookOnOutgoing)
1581+
{
1582+
if (newHook.isFieldPresent(sfHookOnOutgoing))
1583+
newHook.makeFieldAbsent(sfHookOnOutgoing);
1584+
}
1585+
}
1586+
1587+
if (newHookOnIncoming)
1588+
{
1589+
if (*defHookOnIncoming == *newHookOnIncoming)
1590+
{
1591+
if (newHook.isFieldPresent(sfHookOnIncoming))
1592+
newHook.makeFieldAbsent(sfHookOnIncoming);
1593+
}
1594+
}
1595+
15051596
// set the hookcanemit field if it differs from definition
15061597
if (newHookCanEmit)
15071598
{
@@ -1663,7 +1754,19 @@ SetHook::setHook()
16631754

16641755
auto newHookDef = std::make_shared<SLE>(keylet);
16651756
newHookDef->setFieldH256(sfHookHash, *createHookHash);
1666-
newHookDef->setFieldH256(sfHookOn, *newHookOn);
1757+
1758+
// only HookOn or (HookOnOutgoing and HookOnIncoming)
1759+
if (!view().rules().enabled(featureHookOnV2) ||
1760+
(!newHookOnOutgoing && !newHookOnIncoming))
1761+
newHookDef->setFieldH256(sfHookOn, *newHookOn);
1762+
else
1763+
{
1764+
newHookDef->setFieldH256(
1765+
sfHookOnOutgoing, *newHookOnOutgoing);
1766+
newHookDef->setFieldH256(
1767+
sfHookOnIncoming, *newHookOnIncoming);
1768+
}
1769+
16671770
if (newHookCanEmit)
16681771
newHookDef->setFieldH256(
16691772
sfHookCanEmit, *newHookCanEmit);
@@ -1759,17 +1862,49 @@ SetHook::setHook()
17591862

17601863
// change which definition we're using to the new target
17611864
defNamespace = newDefSLE->getFieldH256(sfHookNamespace);
1762-
defHookOn = newDefSLE->getFieldH256(sfHookOn);
1865+
17631866
if (newDefSLE->isFieldPresent(sfHookCanEmit))
17641867
defHookCanEmit = newDefSLE->getFieldH256(sfHookCanEmit);
17651868

17661869
// set the namespace if it differs from the definition namespace
17671870
if (newNamespace && *defNamespace != *newNamespace)
17681871
newHook.setFieldH256(sfHookNamespace, *newNamespace);
17691872

1873+
defHookOn = newDefSLE->getFieldH256(sfHookOn);
1874+
defHookOnIncoming = newDefSLE->getFieldH256(sfHookOnIncoming);
1875+
defHookOnOutgoing = newDefSLE->getFieldH256(sfHookOnOutgoing);
1876+
17701877
// set the hookon field if it differs from definition
1771-
if (newHookOn && *defHookOn != *newHookOn)
1772-
newHook.setFieldH256(sfHookOn, *newHookOn);
1878+
if (newHookOn)
1879+
{
1880+
auto const diffFromDef = defHookOn != *newHookOn;
1881+
auto const hasIncOutgDef =
1882+
*defHookOnIncoming != *defHookOnOutgoing ||
1883+
*newHookOn != *defHookOnIncoming;
1884+
if (diffFromDef || hasIncOutgDef)
1885+
{
1886+
newHook.setFieldH256(sfHookOn, *newHookOn);
1887+
}
1888+
}
1889+
1890+
// set the incoming/outgoing hookon field if it differs from
1891+
// definition
1892+
if (newHookOnIncoming || newHookOnOutgoing)
1893+
{
1894+
auto const diffFromDef =
1895+
*defHookOnIncoming != *newHookOnIncoming ||
1896+
*defHookOnOutgoing != *newHookOnOutgoing;
1897+
auto const hasHookOnDef =
1898+
*newHookOnIncoming != *defHookOn ||
1899+
*newHookOnOutgoing != *defHookOn;
1900+
if (diffFromDef || hasHookOnDef)
1901+
{
1902+
newHook.setFieldH256(
1903+
sfHookOnIncoming, *newHookOnIncoming);
1904+
newHook.setFieldH256(
1905+
sfHookOnOutgoing, *newHookOnOutgoing);
1906+
}
1907+
}
17731908

17741909
// set the hookcanemit field if it differs from definition
17751910
if (newHookCanEmit &&
@@ -1825,8 +1960,8 @@ SetHook::setHook()
18251960
// sfHook: 1 reserve PER non-blank entry
18261961
// sfParameters: 1 reserve PER entry
18271962
// sfGrants are: 1 reserve PER entry
1828-
// sfHookHash, sfHookNamespace, sfHookOn, sfHookCanEmit,
1829-
// sfHookApiVersion, sfFlags: free
1963+
// sfHookHash, sfHookNamespace, sfHookOn, sfHookOnOutgoing,
1964+
// sfHookOnIncoming, sfHookCanEmit sfHookApiVersion, sfFlags: free
18301965

18311966
// sfHookDefinition is not reserved because it is an unowned object,
18321967
// rather the uploader is billed via fee according to the following:
@@ -1988,6 +2123,6 @@ SetHook::setHook()
19882123
}
19892124

19902125
return nsDeleteResult;
1991-
}
2126+
} // namespace ripple
19922127

19932128
} // namespace ripple

0 commit comments

Comments
 (0)