aboutsummaryrefslogtreecommitdiffstats
path: root/lib/sockets.js.map
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-05-17 23:21:39 -0700
committerAdam Soltys <[email protected]>2026-05-17 23:21:39 -0700
commit609fcebe634b499c1133ea26f162c24e1c76d6d4 (patch)
treeb1f483eaaaae6951385479b579ae77639e1c4f44 /lib/sockets.js.map
parent3c4d0b6914bbc7ecf49312a264d55af3c2e2d7a6 (diff)
downloadcoinos-server-609fcebe634b499c1133ea26f162c24e1c76d6d4.tar.gz
coinos-server-609fcebe634b499c1133ea26f162c24e1c76d6d4.zip
serialize limit check + reservation under per-asset mutex
The previous check at debit() read ${type}:limit, compared amount, and deferred any decrement to the next freezeCheck tick (every 10s). That made the check non-atomic: a burst of concurrent withdrawals could each pass the same stale limit value before any reconciliation happened. Combined with the /gateway abuse, this allowed the hot wallet to be drained. withLimitLock() serializes the check + db.decrBy inside a per-type async mutex, and freezeCheck also takes the lock when overwriting limits so its 10s reconciliation can't race in-flight checks. Single-process only; distributed lock or TigerBeetle reservation needed if app ever scales out. Trade-off: decremented limits are not refunded on payment failure — they get reset by the next freezeCheck within 10s. Acceptable false-deny window in exchange for correctness against bursts. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Diffstat (limited to 'lib/sockets.js.map')
0 files changed, 0 insertions, 0 deletions