Summary
enter_reentrancy_guard is documented as needing to be acquired before any state that a reentrant call could observe or act on partway through. In four entrypoints it's called well after the function has already started doing real work:
assert_outcome (lib.rs:962-984): guard entered at line 978, after id allocation.
dispute (lib.rs:1073-1147): guard entered at line 1141, well after committee/policy validation.
register (lib.rs:1180-1289): guard entered at line 1283, after all position/weight validation.
withdraw (lib.rs:1968-2024): guard entered at line 2018, after credit-balance checks.
None of this is currently a demonstrated exploit, everything before each guard-entry point is pure validation against already-committed storage, not a token transfer or a write a reentrant call could race. But it's fragile: any future edit that adds a write or external call earlier in one of these functions (a common kind of change) would silently create a reentrancy window rather than triggering a ReentrancyGuardActive failure, since the guard isn't yet the first thing the function does.
Scope
- Move
enter_reentrancy_guard() to the first line of each of the four listed entrypoints (immediately after require_auth(), matching the ordering convention used elsewhere in this contract for auth-then-guard).
- No behavior change for any currently-passing test; this is a defensive reordering, not a logic change.
- Confirm the existing reentrancy test suite still passes with the guard entered earlier, and add a regression test if the current suite doesn't already cover a reentrant call attempted during the now-guarded early validation window.
Proposed approach
Straightforward reordering: hoist the existing Self::enter_reentrancy_guard(&env)?; call above the validation logic in each of the four functions, no new logic needed.
Summary
enter_reentrancy_guardis documented as needing to be acquired before any state that a reentrant call could observe or act on partway through. In four entrypoints it's called well after the function has already started doing real work:assert_outcome(lib.rs:962-984): guard entered at line 978, after id allocation.dispute(lib.rs:1073-1147): guard entered at line 1141, well after committee/policy validation.register(lib.rs:1180-1289): guard entered at line 1283, after all position/weight validation.withdraw(lib.rs:1968-2024): guard entered at line 2018, after credit-balance checks.None of this is currently a demonstrated exploit, everything before each guard-entry point is pure validation against already-committed storage, not a token transfer or a write a reentrant call could race. But it's fragile: any future edit that adds a write or external call earlier in one of these functions (a common kind of change) would silently create a reentrancy window rather than triggering a
ReentrancyGuardActivefailure, since the guard isn't yet the first thing the function does.Scope
enter_reentrancy_guard()to the first line of each of the four listed entrypoints (immediately afterrequire_auth(), matching the ordering convention used elsewhere in this contract for auth-then-guard).Proposed approach
Straightforward reordering: hoist the existing
Self::enter_reentrancy_guard(&env)?;call above the validation logic in each of the four functions, no new logic needed.