ops: GOA auto-confirm DB-selected withdrawals + debt-headroom filter

This commit is contained in:
Hernâni Marques 2026-09-18 12:18:47 +02:00
parent 65bcddc185
commit 281873a955
No known key found for this signature in database
GPG key ID: CB5738652768F7E9

View file

@ -1,6 +1,11 @@
#!/bin/bash #!/bin/bash
# Auto-confirm bank withdrawals for the community demo pool ONLY (explorer). # Auto-confirm bank withdrawals for the community demo pool ONLY (explorer).
# #
# Discovery: (1) landing watch files (withdraw.uri / withdraw-watch.ids),
# (2) libeufin DB via local psql (selected && !confirmed && username=explorer).
# Watch-file-only misses webui/wallet-selected ops not in the last WATCH_MAX
# IDs — DB scan is required (same idea as testpaysan; here in-CTR, no podman).
#
# Run once: auto-confirm-withdrawals.sh # Run once: auto-confirm-withdrawals.sh
# Loop: auto-confirm-withdrawals.sh --loop [SECS] # Loop: auto-confirm-withdrawals.sh --loop [SECS]
# #
@ -9,6 +14,8 @@
# BANK_USER (default explorer) # BANK_USER (default explorer)
# BANK_PASS or /root/bank-explorer-password.txt # BANK_PASS or /root/bank-explorer-password.txt
# LANDING_DIR (default /var/www/bank-landing) # LANDING_DIR (default /var/www/bank-landing)
# DB_NAME (default libeufin)
# DB_LIMIT max selected IDs from DB per tick (default 40)
# ALLOW_NON_EXPLORER=1 # ALLOW_NON_EXPLORER=1
# WATCH_MAX max IDs kept in withdraw-watch.ids after prune (default 80) # WATCH_MAX max IDs kept in withdraw-watch.ids after prune (default 80)
# QUIET=1 less skip noise (default 1 in --loop) # QUIET=1 less skip noise (default 1 in --loop)
@ -22,6 +29,8 @@ LANDING_DIR="${LANDING_DIR:-/var/www/bank-landing}"
WATCH_FILE="${LANDING_DIR}/withdraw-watch.ids" WATCH_FILE="${LANDING_DIR}/withdraw-watch.ids"
URI_FILE="${LANDING_DIR}/withdraw.uri" URI_FILE="${LANDING_DIR}/withdraw.uri"
WATCH_MAX="${WATCH_MAX:-80}" WATCH_MAX="${WATCH_MAX:-80}"
DB_NAME="${DB_NAME:-libeufin}"
DB_LIMIT="${DB_LIMIT:-40}"
LOCK_FILE="${LOCK_FILE:-/var/run/auto-confirm-withdrawals.lock}" LOCK_FILE="${LOCK_FILE:-/var/run/auto-confirm-withdrawals.lock}"
LOOP=0 LOOP=0
SLEEP=2 SLEEP=2
@ -96,6 +105,45 @@ known_ids() {
fi fi
} }
# Selected, not yet confirmed, owner = explorer only (runs inside goa CTR).
db_selected_explorer_ids() {
if ! command -v psql >/dev/null 2>&1; then
qlog "psql missing — skip DB discovery"
return 0
fi
if ! id -u postgres >/dev/null 2>&1; then
qlog "postgres user missing — skip DB discovery"
return 0
fi
# Prefer affordable amounts (newest-first often hits oversized junk that
# exceeds explorer debt headroom → HTTP 409 Insufficient funds forever).
su -s /bin/bash postgres -c "psql -d ${DB_NAME} -At -c \"
WITH explorer AS (
SELECT a.bank_account_id, a.has_debt, a.balance, a.max_debt
FROM libeufin_bank.bank_accounts a
JOIN libeufin_bank.customers c ON c.customer_id = a.owning_customer_id
WHERE c.username = '${USER}'
LIMIT 1
),
headroom AS (
SELECT CASE WHEN has_debt THEN (max_debt).val - (balance).val
ELSE (max_debt).val + (balance).val END AS val
FROM explorer
)
SELECT w.withdrawal_uuid::text
FROM libeufin_bank.taler_withdrawal_operations w
JOIN explorer e ON e.bank_account_id = w.wallet_bank_account
CROSS JOIN headroom h
WHERE w.selection_done = true
AND w.confirmation_done = false
AND w.aborted = false
AND (w.amount).val <= h.val
ORDER BY (w.amount).val ASC, (w.amount).frac ASC, w.creation_date DESC
LIMIT ${DB_LIMIT};
\"" 2>/dev/null \
| grep -E '^[0-9a-fA-F-]{36}$' || true
}
# Keep file small: drop confirmed/aborted; keep pending/selected + tail # Keep file small: drop confirmed/aborted; keep pending/selected + tail
prune_watch() { prune_watch() {
[ -f "$WATCH_FILE" ] || return 0 [ -f "$WATCH_FILE" ] || return 0
@ -172,16 +220,17 @@ once() {
return 1 return 1
fi fi
# Cap work per loop: last WATCH_MAX ids only (newest at end of file) # Watch files (landing) + DB selected(!confirmed) explorer ops
ids=$( { ids=$( {
[ -f "$URI_FILE" ] && basename "$(tr -d '\n' <"$URI_FILE")" [ -f "$URI_FILE" ] && basename "$(tr -d '\n' <"$URI_FILE")"
if [ -f "$WATCH_FILE" ]; then if [ -f "$WATCH_FILE" ]; then
grep -E '^[0-9a-fA-F-]{36}$' "$WATCH_FILE" | awk 'NF && !seen[$0]++' | tail -n "$WATCH_MAX" grep -E '^[0-9a-fA-F-]{36}$' "$WATCH_FILE" | awk 'NF && !seen[$0]++' | tail -n "$WATCH_MAX"
fi fi
db_selected_explorer_ids
} | awk 'NF && !seen[$0]++' ) } | awk 'NF && !seen[$0]++' )
if [ -z "$ids" ]; then if [ -z "$ids" ]; then
qlog "no withdrawal ids to watch" qlog "no withdrawal ids (selected or watched)"
return 0 return 0
fi fi