Expanding the findings from #71 .
Add SDK-level #[non_reentrant] modifier for ALLOW_REENTRY opt-in contracts
Context
When a contract opts into ALLOW_REENTRY, pallet-revive's default reentrancy reject is bypassed (see #67 ). The contract author now needs to write their own guard, typically a bool locked slot with check-set-clear around the reentrant entry point. This is exactly the OZ nonReentrant pattern.
Notice that "Reentrancy-protected by default" and #[non_reentrant] are two different mechanisms. By default pallet-revive rejects reentrant calls at the runtime/host level, which costs zero contract bytecode . So the typical contract is already protected and pays nothing. #[non_reentrant] exists only for the minority of contracts that deliberately turn that default off via CallFlags::ALLOW_REENTRY.
Scope
Add a method attribute:
#[method]
#[non_reentrant]
fn flash_loan(&mut self, ...) -> Result<(), Error> {
// user body
}
This may use a hidden storage item _reentrancy_locked: Lazy<bool> slot at the contract layout, which is used as a lock shared across all #[non_reentrant] methods in the same contract
Expanding the findings from #71 .
Add SDK-level
#[non_reentrant]modifier forALLOW_REENTRYopt-in contractsContext
When a contract opts into
ALLOW_REENTRY, pallet-revive's default reentrancy reject is bypassed (see #67 ). The contract author now needs to write their own guard, typically a bool locked slot with check-set-clear around the reentrant entry point. This is exactly the OZ nonReentrant pattern.Notice that "Reentrancy-protected by default" and
#[non_reentrant]are two different mechanisms. By default pallet-revive rejects reentrant calls at the runtime/host level, which costs zero contract bytecode . So the typical contract is already protected and pays nothing.#[non_reentrant]exists only for the minority of contracts that deliberately turn that default off viaCallFlags::ALLOW_REENTRY.Scope
Add a method attribute:
This may use a hidden storage item
_reentrancy_locked: Lazy<bool>slot at the contract layout, which is used as a lock shared across all#[non_reentrant]methods in the same contract