Severity: MEDIUM
admin_cancel lacks the atomic compare-and-set status guard that admin_settle has.
Where
src/app/admin_cancel.rs vs src/app/admin_settle.rs.
Problem
admin_settle guards its transition with a conditional update (only acts if the order is still in the expected status), which makes concurrent invocations idempotent. admin_cancel does not have the equivalent guard, so two concurrent admin-cancel requests (or an admin-cancel racing another transition) can both proceed. Combined with the irreversible cancel_hold_invoice side effect (see the "refund before validation" issue), this is worth hardening.
Suggested fix
Mirror admin_settle's CAS pattern in admin_cancel: transition status atomically and only run the LN side effect when the CAS actually updated the row.
Found during the deep review accompanying #803.
Severity: MEDIUM
admin_cancellacks the atomic compare-and-set status guard thatadmin_settlehas.Where
src/app/admin_cancel.rsvssrc/app/admin_settle.rs.Problem
admin_settleguards its transition with a conditional update (only acts if the order is still in the expected status), which makes concurrent invocations idempotent.admin_canceldoes not have the equivalent guard, so two concurrent admin-cancel requests (or an admin-cancel racing another transition) can both proceed. Combined with the irreversiblecancel_hold_invoiceside effect (see the "refund before validation" issue), this is worth hardening.Suggested fix
Mirror
admin_settle's CAS pattern inadmin_cancel: transition status atomically and only run the LN side effect when the CAS actually updated the row.Found during the deep review accompanying #803.