Solia saysA reentrancy guard wraps a function in a mutex flag (NOT_ENTERED → ENTERED → revert if re-entered) — the belt-and-braces companion to checks-effects-interactions.
Even with CEI discipline, complex contracts can have reentrancy paths across functions (one function updates one slot, another reads a stale one). A reentrancy guard is a simple mutex: a state variable starts at NOT_ENTERED, flips to ENTERED on function entry, and reverts if any function annotated with the guard sees it already ENTERED.
OpenZeppelin's ReentrancyGuard uses a single uint slot (cheap with EIP-1153 transient storage). The cost is one warm SSTORE per guarded call. The demo wires up a tiny guard and shows a recursive re-entry being rejected.
Power-ups you unlock
Mutex flag: NOT_ENTERED → ENTERED → revert on re-entry
Reverts cross-function reentrancy too, not just direct
Cost: one warm SSTORE per guarded call
EIP-1153 transient storage makes it nearly free
Defense in depth with checks-effects-interactions
The Reentrancy Reaper attacks — common mistakes
Forgetting to apply the modifier to every entry point
Using a guard with an external call that does NOT need protection (wasted gas)
Confusing reentrancy guard with read-only reentrancy (separate concern)
Trying to skip the guard "because CEI is enough" in complex contracts
Boss battleImplement a nonReentrant wrapper and show it reverts a recursive call into a guarded function.