Skip to content

Control APIs

This page documents the ten control Hook APIs: the functions that terminate hook execution, guard loops, and inspect or influence the hook's position and parameters within the hook chain.

All signatures are copied verbatim from hook/extern.h. Return codes reference the shared error table in ../../glossary; the values quoted below come from

`hook/error.h`.

Execution-termination model

A hook is a WebAssembly function that returns control to the ledger in exactly one of two ways:

  • accept — the originating transaction is applied. Any state changes the hook wrote and any transactions it emitted are kept.
  • rollback — the originating transaction is rejected. State changes and emitted transactions from this hook are discarded.

Both functions terminate the hook immediately: internally they set the hook's exit type and return the special sentinel codes RC_ACCEPT (-20) or RC_ROLLBACK (-19) to the VM, which stops execution. Code after an accept/rollback call in the same path never runs.

If a hook function returns normally (falls off the end of hook()) without calling either, the default exit type is ROLLBACK. Under the fixXahauV3 amendment the default becomes WASM_ERROR instead; either way, not calling accept rejects the transaction. Always call accept explicitly on the success path.

Each hook execution records a metadata entry (sfHookExecution) that captures the outcome:

  • sfHookResult — the exit type as a uint8_t (ExitType: WASM_ERROR=1, ROLLBACK=2, ACCEPT=3; UNSET=0).
  • sfHookReturnCode — the error_code you passed to accept/rollback, stored as uint64_t. Negative values are encoded by setting the most-significant bit (0x8000000000000000 + (-code)), so a returned -16 appears as a large unsigned number.
  • sfHookReturnString — the reason string you passed (see the per-function notes).
  • sfHookInstructionCount, sfHookEmitCount, sfHookStateChangeCount, sfHookHash, etc.

This metadata is how off-ledger tooling learns why a hook accepted or rejected, so the error_code and reason string you pass are your primary debugging channel.


The guard system

WebAssembly on Xahau is metered by a guard mechanism rather than an open-ended gas counter (Guard-type hooks; HookApiVersion 0). Every loop must call _g at its very top, declaring the maximum number of iterations it will run. This makes worst-case execution cost statically computable, so the network can price a SetHook up front and guarantee that hooks halt.

Two enforcement points exist:

  1. Install time (static validation). When a hook is set, the server runs the guard validator over the WASM. It walks the code section and, for every loop opcode (0x03), requires the immediately following instructions to be exactly i32.const <guard_id>, i32.const <maxiter>, call _g. A loop that is missing this prologue, that specifies maxiter == 0, or that calls a function other than _g there is rejected and the SetHook fails (log codes such as GUARD_MISSING). There is a hard limit of 1024 guard calls per hook.

  2. Run time (dynamic enforcement). During execution _g counts calls per guard_id. If a guarded loop exceeds its declared maxiter, _g sets the exit type to ROLLBACK with exit code GUARD_VIOLATION (-16) and terminates the hook. GUARD_VIOLATION in the metadata therefore means "a loop ran more times than it promised."

The developer-facing GUARD(maxiter) / GUARDM(maxiter, n) macros (in hook/macro.h) build the guard_id from the source line number so each loop gets a distinct id; see ../macros. You rarely call _g by hand except for the mandatory _g(1,1) at the top of hook().


Index

FunctionPurpose
acceptTerminate the hook and let the originating transaction proceed.
rollbackTerminate the hook and reject the originating transaction.
_gLoop/branch guard; required at the top of every loop.
hook_accountWrite the AccountID the hook is installed on.
hook_hashWrite the WASM hash of a hook in the chain.
hook_posReturn this hook's position within the hook chain.
hook_paramRead this hook's install-time parameter value by key.
hook_param_setOverride a parameter for a later hook in the chain.
hook_againRequest a weak (post-apply) re-execution of the hook.
hook_skipSkip (or un-skip) a named hook in the chain.