Block Hooks
Blocks hooks are functions (Similar to State transition functions) that are automatically executed before or after the execution of all the actions on the block as per configuration. Hooks are executed once per block and a representation of the same is stored in Block Headers for verification later.
Hooks in Stackr
Our SDK provides a way to create execution hooks for the blocks.
A basic hook in Stackr looks like this:
import { Hook, Hooks } from "@stackr/sdk/machine";
import { CounterState } from "./machine";
const addTwo: Hook<CounterState> = {
handler: ({ state }) => {
state += 2;
return state;
},
};
const minusTwo: Hook<CounterState> = {
handler: ({ state }) => {
state -= 2;
return state;
},
};
export const hooks: Hooks<CounterState> = {
addTwo,
minusTwo,
};
In the above example, we have two hooks addTwo
and minusTwo
. These hooks have a handler, and they take in current state, applies the hook logic & return the new state.
Hooks in Detail
The most important part of the Hooks is the handler
function. This function only has access to the current state & the blockInfo height
, timestamp
& parentHash
. Like State Transition Functions, they should be pure functions too & should return the new state after the applying the logic.
Defining the Hooks for MicroRollup
To configure these hooks, hooks
has to be passed in StateMachine & then pre
& post
hooks can be defined as follows on the MircoRollup :
const mru = await MicroRollup({
config: stackrConfig,
actionSchemas: [UpdateCounterSchema],
stateMachines: [machine],
blockHooks: {
pre: ["addTwo"],
post: ["minusTwo"],
},
});
In this case, we call addTwo
before and minusTwo
after the block is executed. Mutliple hooks can be added for both of the triggers by just passing the hook name as string in the array.
Variables available inside a block hook
There are 3 special variables which always exist inside the handler of a block hook. These can be used by the developer to write the logic of a block hook:
state
block
block.height
block.timestamp
block.parentHash
emit
// Without Destructuring
const superCoolBlockHook: Hook<MachineState> = {
handler: (props) => {
const state = props.blockemitstate
const height = props.block.heightparentHashtimestamp
},
};
// With Destructuring
const anotherSuperCoolBlockHook: Hook<MachineState> = {
handler: ({ sstate }) => {
},
};
State
state
: The entire current state of the state machine in wrapped format. This is the state that the block hook is supposed to modify.
Block Properties
A block
object containing the current block height, timestamp and the parent block's hash is passed as an argument to the hook. These can be used to generate pseudo-random numbers or to implement time-based logic.
-
block.height
: The height of the block. -
block.timestamp
: The timestamp of the block. -
block.parentHash
: The hash of the parent block of the block.
Custom Execution Logs
The emit
variable passed to a hook is a method that can be used to record custom execution logs (later accessible at block.hooksLogs
).
Example usage:
const checkEven: Hook<CounterState> = {
handler: ({ state, emit }) => {
if (state % 2 === 0) {
emit({ name: "is_even", value: state });
}
return state;
},
};