diff --git a/scripts/taler-bank/auto-confirm-withdrawals.sh b/scripts/taler-bank/auto-confirm-withdrawals.sh index a46c523..c75817c 100755 --- a/scripts/taler-bank/auto-confirm-withdrawals.sh +++ b/scripts/taler-bank/auto-confirm-withdrawals.sh @@ -1,6 +1,11 @@ #!/bin/bash # 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 # Loop: auto-confirm-withdrawals.sh --loop [SECS] # @@ -9,6 +14,8 @@ # BANK_USER (default explorer) # BANK_PASS or /root/bank-explorer-password.txt # 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 # WATCH_MAX max IDs kept in withdraw-watch.ids after prune (default 80) # 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" URI_FILE="${LANDING_DIR}/withdraw.uri" 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}" LOOP=0 SLEEP=2 @@ -96,6 +105,45 @@ known_ids() { 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 prune_watch() { [ -f "$WATCH_FILE" ] || return 0 @@ -172,16 +220,17 @@ once() { return 1 fi - # Cap work per loop: last WATCH_MAX ids only (newest at end of file) + # Watch files (landing) + DB selected(!confirmed) explorer ops ids=$( { [ -f "$URI_FILE" ] && basename "$(tr -d '\n' <"$URI_FILE")" if [ -f "$WATCH_FILE" ]; then grep -E '^[0-9a-fA-F-]{36}$' "$WATCH_FILE" | awk 'NF && !seen[$0]++' | tail -n "$WATCH_MAX" fi + db_selected_explorer_ids } | awk 'NF && !seen[$0]++' ) if [ -z "$ids" ]; then - qlog "no withdrawal ids to watch" + qlog "no withdrawal ids (selected or watched)" return 0 fi