Appearance
Flags (on the sfHook object)
Purpose: a 32-bit bitfield inside each sfHook entry carrying SetHook-specific control bits (hsoDELETE/hsoNSDELETE requirements, hsoINSTALL/hsoCREATE override permission) and one runtime bit, hsfCOLLECT, that persists onto the ledger and gates weak-execution hook chains. This is a different field from the transaction's own top-level sfFlags — see the warning below.
Field declaration: UINT32, code 2.
sfFlags is a generic, protocol-wide field, not hook-specific — it is declared once and reused as a common field on every transaction type and (automatically) on every ledger entry type. It is soeOPTIONAL on sfHook and is not listed explicitly in ltHOOK_DEFINITION's template because sfFlags is one of the fields auto-attached to every LEDGER_ENTRY (alongside sfLedgerIndex, sfLedgerEntryType, sfRemarks) — yet it is still legally stored and read on a ltHOOK_DEFINITION SLE (see below).
Don't confuse this with the transaction-level sfFlags. A SetHook transaction, like every transaction, carries its own top-level sfFlags (the standard signing/canonical-signature bits). That field is checked independently, unrelated to any sfHook object's flags, and gated by fixInvalidTxFlags.
SetHook defines no tfXxx transaction flags of its own, so this simply rejects any bit outside the universal mask (e.g. tfFullyCanonicalSig) on the transaction itself. Everything else on this page is about the per-sfHook-object sfFlags, which uses an entirely separate bit namespace (hsf*, below).
Hook-set flag values — HookSetFlags:
| Flag | Value | Meaning |
|---|---|---|
hsfOVERRIDE | 0x1 | Permission bit: this operation may replace/delete a hash already occupying the chain slot. |
hsfNSDELETE | 0x2 | Request bit: destroy a namespace's Hook State as part of this operation (see HookNamespace for full mechanics, including its use as a side effect on non-hsoNSDELETE operations). |
hsfCOLLECT | 0x4 | Persistent bit: marks this hook eligible to run during weak (non-strong) "collect" execution. |
Per-operation legality:
hsoNSDELETE:sfFlagsrequired, and must equal exactlyhsfNSDELETE— no other bit, includinghsfOVERRIDEorhsfCOLLECT, may accompany it (NSDELETE_FLAGS).hsoDELETE:sfFlagsrequired and must includehsfOVERRIDE(OVERRIDE_MISSINGotherwise); allowed bits are limited tohsfOVERRIDE | hsfNSDELETE | hsfCOLLECT— any other bit isFLAGS_INVALID. A missing flag and an all-1s2147483648value are both rejected.hsoUPDATE:hsfOVERRIDEis forbidden outright;hsfNSDELETEis allowed only together with a newly suppliedsfHookNamespacein the same entry (both conditions checked in one guard,FLAGS_INVALID). An override flag on update andNSDELETEwithout a namespace are both rejected.hsoINSTALL/hsoCREATE: validation places no explicit restriction onsfFlagsfor these two — buthsfOVERRIDEis enforced separately, at apply time, as the permission to replace whatever currently occupies the target chain slot:tecREQUIRES_FLAGif a hook already exists there andhsfOVERRIDEis absent. An install without override and a second create without override both producetecREQUIRES_FLAG.
What actually gets persisted — control bits are stripped before storage on hsoCREATE/hsoINSTALL; hsoUPDATE stores the raw value, but validation makes the two control bits unreachable there anyway. Control-only bits are removed before storage.
This stripped value (effectively just hsfCOLLECT plus any undefined higher bits) is what gets written to the ledger for hsoCREATE's new ltHOOK_DEFINITION and for hsoINSTALL's per-account entry. hsoUPDATE instead stores the raw, unstripped submitted value. This looks like it could leave a stray hsfOVERRIDE/hsfNSDELETE bit on the ledger, but operation inference and the hsoUPDATE validation guard prevent that in a transaction that actually validates: operation inference only returns hsoUPDATE when either sfHookNamespace is absent or hsfNSDELETE is unset (any (Namespace present, hsfNSDELETE set) pair is classified hsoNSDELETE instead), and hsoUPDATE's own validation rejects flags & hsfNSDELETE whenever sfHookNamespace is absent. The only namespace/flag combination that reaches hsoUPDATE validation with hsfNSDELETE set is therefore exactly the one the guard rejects — so hsfNSDELETE can never survive into an applied hsoUPDATE, and hsfOVERRIDE is rejected outright regardless of sfHookNamespace. Raw-vs-stripped storage is a real difference in the code, but it has no observable effect for hsoUPDATE in practice, since validation already guarantees both control bits are absent by the time the apply loop runs.
Runtime use — hsfCOLLECT gates weak execution. Both fee calculation and actual execution read a hook chain entry's stored sfFlags (falling back to the definition's sfFlags if the entry has none) and skip non-strong ("weak"/collect-only) invocations that lack hsfCOLLECT.
The fee-estimation counterpart is identical in spirit, gating whether a hook's fee is even added when only "collect calls" are being priced. This is the mechanism that lets a hook opt in to firing during weakly-executed (TSH/collect) transaction processing, as referenced from HookOn's execution-mode discussion.
Common mistakes:
- Setting the transaction's own top-level
Flagsfield expecting it to control hook behavior —hsf*bits only exist inside eachsfHookobject's ownFlagssub-field. - Assuming
hsoINSTALL/hsoCREATEforbid arbitrary flag bits the wayhsoDELETE/hsoNSDELETEdo. They don't restrict the value at validation time — the only enforcement ishsfOVERRIDE's apply-time permission check. - Assuming
hsoUPDATE's raw (unstripped) flag storage meanshsfNSDELETEcan end up persisted on a hook entry. Validation guarantees it can't: operation inference reclassifies any(Namespace present, hsfNSDELETE set)pair ashsoNSDELETE, andhsoUPDATE's own guard rejects the only remaining case (hsfNSDELETEset withsfHookNamespaceabsent). - Forgetting
hsoNSDELETErejects any extra bit, includinghsfOVERRIDE/hsfCOLLECT— it must be exactlyhsfNSDELETE, not merely "include" it.
Related documents
- HookNamespace — full
hsfNSDELETEdeletion mechanics, including its side-effect behavior on non-hsoNSDELETEoperations. - HookOn — the strong/weak execution model
hsfCOLLECTplugs into. - Operation Matrix — full per-operation field/flag matrix.