Appearance
HookCanEmit
Purpose: restricts which transaction types a hook is permitted to emit(), using the identical bit encoding and evaluation function as HookOn.
Amendment gating: featureHookCanEmit is supported with VoteBehavior::DefaultNo. If the field is present in an sfHook object without the amendment enabled, the whole SetHook operation is rejected with temDISABLED.
Validation: Absence is treated as a no-op because HookCanEmit is optional for backward compatibility. There is no length or shape validation beyond it being a UINT256, and it is subject to the same hsoDELETE/hsoNSDELETE exclusion as HookOn.
Runtime semantics. The emitted transaction's type and the hook's effective HookCanEmit value are evaluated identically to HookOn.
The same active-low-except-ttHOOK_SET rule from HookOn therefore applies here too.
Default value. Unlike HookOn (default all-zero), HookCanEmit defaults to a value with only bit 22 (ttHOOK_SET) set.
Under the HookOn evaluation rule, 1<<22 inverts to all-1s, so the default allows every transaction type to be emitted, including ttHOOK_SET. There is no directional resolution: the effective value is selected from the sfHook entry, then ltHOOK_DEFINITION, then the hardcoded default, with no incoming/outgoing split.
Enforcement point. The permission is checked inside the emit() host function. A disallowed emit returns EMISSION_FAILURE (-11) from emit() — the same error code documented in overview.md's error table — not a rollback; the hook must check the return value itself.
Worked examples (values reflect actual emit() results in a running hook):
HookCanEmit value | Effect |
|---|---|
| (absent) | 0x0...400000 (bit 22 only) → default → all types emittable, including ttHOOK_SET |
0x0...400000 (bit 22 only, set explicitly) | same as absent — this is the default |
0x00...00 (all zero) | Everything except ttHOOK_SET is emittable (Payment/AccountSet succeed, emitting a SetHook returns EMISSION_FAILURE) |
0xFF...FF (all one) | Only ttHOOK_SET is emittable (Payment/AccountSet return EMISSION_FAILURE, emitting a SetHook succeeds) |
Common mistakes:
- Assuming an absent
HookCanEmitis maximally restrictive. It is maximally permissive — it allows emitting everything,SetHookincluded. - Assuming
HookCanEmit = 0blocks all emission. It blocks onlySetHookemission; every other type remains emittable. - Forgetting
canEmitsharesHookOn's active-high quirk for bit 22 — an all-0xFFHookCanEmitlooks maximally permissive but is in fact maximally restrictive (onlySetHookallowed).