exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

test-auditor.sh (82025B)


      1 #!/bin/bash
      2 #
      3 #  This file is part of TALER
      4 #  Copyright (C) 2014-2025 Taler Systems SA
      5 #
      6 #  TALER is free software; you can redistribute it and/or modify it under the
      7 #  terms of the GNU General Public License as published by the Free Software
      8 #  Foundation; either version 3, or (at your option) any later version.
      9 #
     10 #  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     11 #  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     12 #  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     13 #
     14 #  You should have received a copy of the GNU General Public License along with
     15 #  TALER; see the file COPYING.  If not, If not, see <http://www.gnu.org/license>
     16 #
     17 #
     18 # shellcheck disable=SC2317
     19 # shellcheck disable=SC1091
     20 #
     21 #
     22 # Setup database which was generated from a perfectly normal
     23 # exchange-wallet interaction and run the auditor against it.
     24 #
     25 # Check that the auditor report is as expected.
     26 #
     27 # Requires 'jq' tool and Postgres superuser rights!
     28 set -eu
     29 #set -x
     30 
     31 # Set of numbers for all the testcases.
     32 # When adding new tests, increase the last number:
     33 ALL_TESTS=$(seq 0 31)
     34 
     35 # $TESTS determines which tests we should run.
     36 # This construction is used to make it easy to
     37 # only run a subset of the tests. To only run a subset,
     38 # pass the numbers of the tests to run as the FIRST
     39 # argument to test-auditor.sh, i.e.:
     40 #
     41 # $ test-auditor.sh "1 3"
     42 #
     43 # to run tests 1 and 3 only.  By default, all tests are run.
     44 #
     45 TESTS=${1:-$ALL_TESTS}
     46 
     47 export TALER_AUDITOR_TOKEN="secret-token:D4CST1Z6AHN3RT03M0T9NSTF2QGHTB5ZD2D3RYZB4HAWG8SX0JEFWBXCKXZHMB7Y3Z7KVFW0B3XPXD5BHCFP8EB0R6CNH2KAWDWVET0"
     48 # Make taler-auditor-httpd require the token the requests below send.
     49 export TALER_AUDITOR_ACCESS_TOKEN="${TALER_AUDITOR_TOKEN}"
     50 export TALER_AUDITOR_SALT="64S36D1N6RVKGC9J6CT3ADHQ70RK4CSM6MV3EE1H68SK8D9P6WW32CHK6GTKCDSR64S36D1N6RVKGC9J6CT3ADHQ70RK4CSM6MV3EE0"
     51 
     52 # Global variable to run the auditor processes under valgrind
     53 # VALGRIND=valgrind
     54 VALGRIND=""
     55 
     56 . setup.sh
     57 
     58 
     59 # Cleanup exchange and libeufin between runs.
     60 function cleanup()
     61 {
     62     if [ -n "${EPID:-}" ]
     63     then
     64         echo -n "Stopping exchange $EPID..."
     65         kill -TERM "$EPID"
     66         wait "$EPID" || true
     67         echo "DONE"
     68         unset EPID
     69     fi
     70     stop_libeufin &> /dev/null
     71 }
     72 
     73 # Cleanup to run whenever we exit
     74 function exit_cleanup()
     75 {
     76     jobs
     77     if [ -n "${POSTGRES_PATH:-}" ]
     78     then
     79         echo -n "Stopping Postgres at ${POSTGRES_PATH} ..."
     80         "${POSTGRES_PATH}/pg_ctl" \
     81                         -D "$TMPDIR" \
     82                         --log="${MY_TMP_DIR}/pg_ctl.log" \
     83                         stop \
     84             &> ${MY_TMP_DIR}/pg_ctl.out \
     85             || true
     86         echo "DONE"
     87     fi
     88     echo -n "Running exit-cleanup ..."
     89     cleanup
     90     for n in $(jobs -p)
     91     do
     92         kill "$n" 2> /dev/null || true
     93     done
     94     wait || true
     95     echo "DONE"
     96 }
     97 
     98 # Install cleanup handler (except for kill -9)
     99 trap exit_cleanup EXIT
    100 
    101 
    102 function await_bank () {
    103     for n in $(seq 1 80)
    104     do
    105         echo -n "."
    106         sleep 0.1
    107         OK=1
    108         wget http://localhost:8082/ \
    109              -o /dev/null \
    110              -O /dev/null \
    111              >/dev/null \
    112             && break
    113         OK=0
    114     done
    115     if [ 1 != "$OK" ]
    116     then
    117         exit_skip "Failed to launch libeufin-bank"
    118     fi
    119  }
    120 
    121 # Operations to run before the actual audit
    122 function pre_audit () {
    123     # Launch bank
    124     echo -n "Launching libeufin-bank"
    125     export CONF
    126     export MY_TMP_DIR
    127     launch_libeufin
    128     await_bank
    129     echo " DONE"
    130 
    131     if [ "${1:-no}" = "aggregator" ]
    132     then
    133         echo -n "Running exchange aggregator ..."
    134         taler-exchange-aggregator \
    135             -y \
    136             -L "INFO" \
    137             -t \
    138             -c "$CONF" \
    139             2> "${MY_TMP_DIR}/aggregator.log" \
    140             || exit_fail "FAIL"
    141         echo " DONE"
    142         echo -n "Running exchange closer ..."
    143         taler-exchange-closer \
    144             -L "INFO" \
    145             -t \
    146             -c "$CONF" \
    147             2> "${MY_TMP_DIR}/closer.log" \
    148             || exit_fail "FAIL"
    149         echo " DONE"
    150         echo -n "Running exchange transfer ..."
    151         taler-exchange-transfer \
    152             -L "INFO" \
    153             -t \
    154             -c "$CONF" \
    155             2> "${MY_TMP_DIR}/transfer.log" \
    156             || exit_fail "FAIL"
    157         echo " DONE"
    158     fi
    159 }
    160 
    161 # actual audit run
    162 function audit_only () {
    163     # Run the auditor!
    164     echo -n "Running audit(s) ..."
    165 
    166     # Restart so that first run is always fresh, and second one is incremental
    167     taler-auditor-dbinit \
    168         -r \
    169         -c "$CONF"
    170     $VALGRIND taler-helper-auditor-aml \
    171               -i \
    172               -L DEBUG \
    173               -c "$CONF" \
    174               -t \
    175               > "${MY_TMP_DIR}/test-audit-aml.out" \
    176               2> "${MY_TMP_DIR}/test-audit-aml.err" \
    177         || exit_fail "aml audit failed (see ${MY_TMP_DIR}/test-audit-aml.*)"
    178     echo -n "."
    179     $VALGRIND taler-helper-auditor-aml \
    180               -i \
    181               -L DEBUG \
    182               -c "$CONF" \
    183               -t \
    184               > "${MY_TMP_DIR}/test-audit-aml-inc.out" \
    185               2> "${MY_TMP_DIR}/test-audit-aml-inc.err" \
    186         || exit_fail "incremental aml audit failed (see ${MY_TMP_DIR}/test-audit-aml-inc.*)"
    187     echo -n "."
    188     $VALGRIND taler-helper-auditor-aggregation \
    189               -L DEBUG \
    190               -c "$CONF" \
    191               -t \
    192               > "${MY_TMP_DIR}/test-audit-aggregation.out" \
    193               2> "${MY_TMP_DIR}/test-audit-aggregation.err" \
    194         || exit_fail "aggregation audit failed (see ${MY_TMP_DIR}/test-audit-aggregation.*)"
    195     echo -n "."
    196     $VALGRIND taler-helper-auditor-aggregation \
    197               -L DEBUG \
    198               -c "$CONF" \
    199               -t \
    200               > "${MY_TMP_DIR}/test-audit-aggregation-inc.out" \
    201               2> "${MY_TMP_DIR}/test-audit-aggregation-inc.err" \
    202         || exit_fail "incremental aggregation audit failed (see ${MY_TMP_DIR}/test-audit-aggregation-inc.*)"
    203     echo -n "."
    204     $VALGRIND taler-helper-auditor-coins \
    205               -L DEBUG \
    206               -c "$CONF" \
    207               -t \
    208               > "${MY_TMP_DIR}/test-audit-coins.out" \
    209               2> "${MY_TMP_DIR}/test-audit-coins.err" \
    210         || exit_fail "coin audit failed (see ${MY_TMP_DIR}/test-audit-coins.*)"
    211     echo -n "."
    212     $VALGRIND taler-helper-auditor-coins \
    213               -L DEBUG  \
    214               -c "$CONF" \
    215               -t \
    216               > "${MY_TMP_DIR}/test-audit-coins-inc.out" \
    217               2> "${MY_TMP_DIR}/test-audit-coins-inc.err" \
    218         || exit_fail "incremental coin audit failed (see ${MY_TMP_DIR}/test-audit-coins-inc.*)"
    219     echo -n "."
    220     $VALGRIND taler-helper-auditor-deposits \
    221               -L DEBUG \
    222               -c "$CONF" \
    223               -t \
    224               > "${MY_TMP_DIR}/test-audit-deposits.out" \
    225               2> "${MY_TMP_DIR}/test-audit-deposits.err" \
    226         || exit_fail "deposits audit failed (see ${MY_TMP_DIR}/test-audit-deposits.*)"
    227     echo -n "."
    228     $VALGRIND taler-helper-auditor-deposits \
    229               -L DEBUG \
    230               -c "$CONF" \
    231               -t \
    232               > "${MY_TMP_DIR}/test-audit-deposits-inc.out" \
    233               2> "${MY_TMP_DIR}/test-audit-deposits-inc.err" \
    234         || exit_fail "incremental deposits audit failed (see ${MY_TMP_DIR}/test-audit-deposits-inc.*)"
    235     echo -n "."
    236     $VALGRIND taler-helper-auditor-reserves \
    237               -i \
    238               -L DEBUG \
    239               -c "$CONF" \
    240               -t \
    241               > "${MY_TMP_DIR}/test-audit-reserves.out" \
    242               2> "${MY_TMP_DIR}/test-audit-reserves.err" \
    243         || exit_fail "reserves audit failed (see ${MY_TMP_DIR}/test-audit-reserves.*)"
    244     echo -n "."
    245     $VALGRIND taler-helper-auditor-reserves \
    246               -i \
    247               -L DEBUG \
    248               -c "$CONF" \
    249               -t \
    250               > "${MY_TMP_DIR}/test-audit-reserves-inc.out" \
    251               2> "${MY_TMP_DIR}/test-audit-reserves-inc.err" \
    252         || exit_fail "incremental reserves audit failed (see ${MY_TMP_DIR}/test-audit-reserves-inc.*)"
    253     echo -n "."
    254     $VALGRIND taler-helper-auditor-wire-credit \
    255               -i \
    256               -L DEBUG \
    257               -c "$CONF" \
    258               -t \
    259               > "${MY_TMP_DIR}/test-audit-wire-credit.out" \
    260               2> "${MY_TMP_DIR}/test-audit-wire-credit.err" \
    261         || exit_fail "wire credit audit failed (see ${MY_TMP_DIR}/test-audit-wire-credit.*)"
    262     echo -n "."
    263     $VALGRIND taler-helper-auditor-wire-credit \
    264               -i \
    265               -L DEBUG \
    266               -c "$CONF" \
    267               -t \
    268               > "${MY_TMP_DIR}/test-audit-wire-credit-inc.out" \
    269               2> "${MY_TMP_DIR}/test-audit-wire-credit-inc.err" \
    270         || exit_fail "wire credit audit inc failed (see ${MY_TMP_DIR}/test-audit-wire-credit-inc.*)"
    271     echo -n "."
    272     $VALGRIND taler-helper-auditor-wire-debit \
    273               -i \
    274               -L DEBUG \
    275               -c "$CONF" \
    276               -t \
    277               > "${MY_TMP_DIR}/test-audit-wire-debit.out" \
    278               2> "${MY_TMP_DIR}/test-audit-wire-debit.err" \
    279         || exit_fail "wire debit audit failed (see ${MY_TMP_DIR}/test-audit-wire-debit.*)"
    280     echo -n "."
    281     $VALGRIND taler-helper-auditor-wire-debit \
    282               -i \
    283               -L DEBUG \
    284               -c "$CONF" \
    285               -t \
    286               > "${MY_TMP_DIR}/test-audit-wire-debit-inc.out" \
    287               2> "${MY_TMP_DIR}/test-audit-wire-debit-inc.err" \
    288         || exit_fail "wire debit audit inc failed (see ${MY_TMP_DIR}/test-audit-wire-debit-inc.*)"
    289     echo -n "."
    290     $VALGRIND taler-helper-auditor-purses \
    291              -i \
    292              -L DEBUG \
    293              -c "$CONF" \
    294              -t \
    295              > "${MY_TMP_DIR}/test-audit-purses.out" \
    296              2> "${MY_TMP_DIR}/test-audit-purses.err" \
    297        || exit_fail "audit purses failed"
    298     echo -n "."
    299     $VALGRIND taler-helper-auditor-purses \
    300               -i \
    301               -L DEBUG \
    302               -c "$CONF" \
    303               -t \
    304               > "${MY_TMP_DIR}/test-audit-purses-inc.out" \
    305               2> "${MY_TMP_DIR}/test-audit-purses-inc.err" \
    306         || exit_fail "audit purses inc failed"
    307     echo -n "."
    308     $VALGRIND taler-helper-auditor-transfer \
    309              -i \
    310              -L DEBUG \
    311              -c "$CONF" \
    312              -t \
    313              > "${MY_TMP_DIR}/test-audit-transfer.out" \
    314              2> "${MY_TMP_DIR}/test-audit-transfer.err" \
    315        || exit_fail "audit transfer failed"
    316     echo -n "."
    317     $VALGRIND taler-helper-auditor-transfer \
    318               -i \
    319               -L DEBUG \
    320               -c "$CONF" \
    321               -t \
    322               > "${MY_TMP_DIR}/test-audit-transfer-inc.out" \
    323               2> "${MY_TMP_DIR}/test-audit-transfer-inc.err" \
    324         || exit_fail "audit transfer inc failed"
    325     echo -n "."
    326 
    327     echo " DONE"
    328 }
    329 
    330 
    331 # Cleanup to run after the auditor
    332 function post_audit () {
    333     taler-exchange-dbinit \
    334         -c "$CONF" \
    335         -g \
    336         || exit_fail "exchange DB GC failed"
    337     cleanup
    338 }
    339 
    340 
    341 # Run audit process on current database, including report
    342 # generation.  Pass "aggregator" as $1 to run
    343 # $ taler-exchange-aggregator
    344 # before auditor (to trigger pending wire transfers).
    345 # Pass "drain" as $2 to run a drain operation as well.
    346 function run_audit () {
    347     pre_audit "${1:-no}"
    348     if [ "${2:-no}" = "drain" ]
    349     then
    350         echo -n "Starting exchange..."
    351         taler-exchange-httpd \
    352             -c "${CONF}" \
    353             -L INFO \
    354             2> "${MY_TMP_DIR}/exchange-httpd-drain.err" &
    355         EPID=$!
    356 
    357         # Wait for exchange service to be available
    358         for n in $(seq 1 50)
    359         do
    360             echo -n "."
    361             sleep 0.1
    362             OK=0
    363             # exchange
    364             wget "http://localhost:8081/config" \
    365                  -o /dev/null \
    366                  -O /dev/null \
    367                  >/dev/null \
    368                 || continue
    369             OK=1
    370             break
    371         done
    372         echo "... DONE."
    373         export CONF
    374 
    375         echo -n "Running taler-exchange-offline drain "
    376 
    377         taler-exchange-offline \
    378             -L DEBUG \
    379             -c "${CONF}" \
    380             drain TESTKUDOS:0.1 \
    381             exchange-account-1 payto://iban/DE12500105170648489890?receiver-name=Merchant43 \
    382             upload \
    383             2> "${MY_TMP_DIR}/taler-exchange-offline-drain.log" \
    384             || exit_fail "offline draining failed"
    385         kill -TERM "$EPID"
    386         wait "$EPID" || true
    387         unset EPID
    388         echo -n "Running taler-exchange-drain ..."
    389         printf "\n" | taler-exchange-drain \
    390                         -L DEBUG \
    391                         -c "$CONF" \
    392                         2> "${MY_TMP_DIR}/taler-exchange-drain.log" \
    393             || exit_fail "FAIL"
    394         echo " DONE"
    395 
    396         echo -n "Running taler-exchange-transfer ..."
    397         taler-exchange-transfer \
    398             -L INFO \
    399             -t \
    400             -c "$CONF" \
    401             2> "${MY_TMP_DIR}/drain-transfer.log" \
    402             || exit_fail "FAIL"
    403         echo " DONE"
    404     fi
    405     audit_only
    406     post_audit
    407 }
    408 
    409 
    410 function stop_auditor_httpd() {
    411   if [ -n "${APID:-}" ]
    412   then
    413       echo -n "Stopping auditor $APID..."
    414       kill -TERM "$APID"
    415       wait "$APID" || true
    416       echo "DONE"
    417       unset APID
    418   fi
    419 }
    420 
    421 
    422 # Do a full reload of the (original) database
    423 function full_reload()
    424 {
    425     echo -n "Doing full reload of the database (loading ${BASEDB}.sql into $DB at ${PGHOST:-})... "
    426     dropdb -f "$DB" &>> ${MY_TMP_DIR}/drop.log || true
    427     createdb -T template0 "$DB" \
    428         || exit_skip "could not create database $DB (at ${PGHOST:-})"
    429     # Import pre-generated database, -q(ietly) using single (-1) transaction
    430     psql -Aqt "$DB" \
    431          -q \
    432          -1 \
    433          -f "${BASEDB}.sql" \
    434          &>> ${MY_TMP_DIR}/postgresql-reload.log \
    435         || exit_skip "Failed to load database $DB from ${BASEDB}.sql"
    436     echo "DONE"
    437     # Technically, this call shouldn't be needed as libeufin should already be stopped here...
    438     stop_libeufin
    439     stop_auditor_httpd
    440 }
    441 
    442 function run_auditor_httpd() {
    443   echo -n "Starting auditor..."
    444   $VALGRIND taler-auditor-httpd \
    445       -c "${CONF}" \
    446       -L INFO \
    447       2> "${MY_TMP_DIR}/auditor-httpd.err" &
    448   APID=$!
    449 
    450   # Wait for auditor service to be available
    451   for n in $(seq 1 50)
    452   do
    453       echo -n "."
    454       sleep 0.2
    455       OK=0
    456       # auditor
    457       wget "http://localhost:8083/config" \
    458            -o /dev/null \
    459            -O /dev/null \
    460            >/dev/null \
    461           || continue
    462       OK=1
    463       break
    464   done
    465   echo "... DONE."
    466   wget "http://localhost:8083/webui/" \
    467        -o /dev/null \
    468        -O /dev/null \
    469        >/dev/null \
    470       || exit_fail "Auditor WebUI is not available under /webui/"
    471   curl -sS -f \
    472        -H "Accept: application/json" \
    473        -H "Authorization: Bearer ${TALER_AUDITOR_TOKEN}" \
    474        -o /dev/null \
    475        "http://localhost:8083/monitoring/coin-inconsistencies" \
    476       || exit_fail "Auditor monitoring endpoint rejects default pagination"
    477 }
    478 
    479 
    480 function check_auditor_running() {
    481   ARUNSTATUS=$(curl -Is http://localhost:8083/config | head -1)
    482   if [ -n "${ARUNSTATUS:-}" ]
    483     then
    484       echo "Auditor running"
    485     else
    486       echo "Auditor not running, starting it"
    487       run_auditor_httpd
    488   fi
    489   unset ARUNSTATUS
    490 }
    491 
    492 function call_endpoint() {
    493     if [ -n "${2+x}" ]
    494     then
    495         curl -s -H "Accept: application/json" -H "Authorization: Bearer ${TALER_AUDITOR_TOKEN}" -o "${MY_TMP_DIR}/${2}.json" "localhost:8083/monitoring/${1}?limit=50&balance_key=${2}"
    496         echo "endpoint ${1} called (with balance_key)... "
    497     else
    498         curl -s -H "Accept: application/json" -H "Authorization: Bearer ${TALER_AUDITOR_TOKEN}" -o "${MY_TMP_DIR}/${1}.json" "localhost:8083/monitoring/${1}?limit=50"
    499         echo "endpoint ${1} called... "
    500     fi
    501 }
    502 
    503 
    504 function check_balance() {
    505     call_endpoint "balances" "$1"
    506     BAL=$(jq -r .records[0].balance_value < "${MY_TMP_DIR}/${1}.json")
    507     if [ "$BAL" != "$2" ]
    508     then
    509         exit_fail "$3 (got $BAL, wanted $2)"
    510     fi
    511     echo "PASS"
    512 }
    513 
    514 
    515 function check_not_balance() {
    516     call_endpoint "balances" "$1"
    517     BAL=$(jq -r .records[0].balance_value < "${MY_TMP_DIR}/${1}.json")
    518     if [ "$BAL" = "$2" ]
    519     then
    520         exit_fail "$3 (got $BAL, wanted NOT $2)"
    521     fi
    522     echo "PASS"
    523 }
    524 
    525 
    526 function check_report() {
    527     call_endpoint "$1"
    528     VAL=$(jq -r .records[0].\"$2\" < "${MY_TMP_DIR}/${1}.json")
    529     if [ "$VAL" != "$3" ]
    530     then
    531         exit_fail "$1::$2 (got $VAL, wanted $3)"
    532     fi
    533     echo "PASS"
    534 }
    535 
    536 # Check that at least one entry of report $1 has field $2 set to $3.
    537 # Unlike check_report, this does not depend on the order in which the
    538 # auditor inserted its findings: one fault can legitimately be reported
    539 # against several operations (a coin with a bad denomination signature is
    540 # flagged once per operation that used it).
    541 function check_report_any() {
    542     call_endpoint "$1"
    543     jq -e --arg want "$3" "any(.records[]; .\"$2\" == \$want)" \
    544        < "${MY_TMP_DIR}/${1}.json" \
    545        > /dev/null \
    546         || exit_fail "$1::$2 (no entry with value $3)"
    547     echo "PASS"
    548 }
    549 
    550 function check_no_report() {
    551     call_endpoint "$1"
    552     jq -e .records[0] \
    553        < "${MY_TMP_DIR}/${1}.json" \
    554        > /dev/null \
    555        && exit_fail "Wanted empty report for $1, but got incidents"
    556     echo "PASS"
    557 }
    558 
    559 function check_report_neg() {
    560     call_endpoint "$1"
    561     VAL=$(jq -r .records[0].\"$2\" < "${MY_TMP_DIR}/${1}.json")
    562     if [ "$VAL" == "$3" ]
    563     then
    564         exit_fail "$1::$2 (got $VAL, wanted $3)"
    565     fi
    566     echo "PASS"
    567 }
    568 
    569 function check_row() {
    570     call_endpoint "$1"
    571     if [ -n "${3+x}" ]
    572     then
    573         RID="$2"
    574         WANT="$3"
    575     else
    576         RID="row_id"
    577         WANT="$2"
    578     fi
    579     ROW=$(jq -r .records[0].\"${RID}\" < "${MY_TMP_DIR}/${1}.json")
    580     if [ "$ROW" != "$WANT" ]
    581     then
    582         exit_fail "Row ${1} wrong (got ${ROW}, wanted ${WANT})"
    583     fi
    584     echo "PASS"
    585 }
    586 
    587 
    588 function test_0() {
    589 
    590     echo "===========0: normal run with aggregator==========="
    591     run_audit aggregator
    592     check_auditor_running
    593 
    594     echo "Checking output"
    595 
    596     # if an emergency was detected, that is a bug and we should fail
    597     echo -n "Test for emergencies... "
    598     check_no_report "emergencies"
    599     echo -n "Test for emergencies by count... "
    600     check_no_report "emergencies-by-count"
    601     echo -n "Test for wire inconsistencies... "
    602     check_no_report "denomination-key-validity-withdraw-inconsistencies"
    603     echo -n "Test for deposit confirmation problems... "
    604     check_no_report "deposit-confirmations"
    605 
    606     # Just to test the endpoint and for logging ...
    607     call_endpoint "balances"
    608 
    609     echo -n "Testing bad sig loss balance... "
    610     check_balance \
    611         "aggregation_total_bad_sig_loss" \
    612         "TESTKUDOS:0" \
    613         "Wrong total bad sig loss from aggregation, got unexpected loss"
    614 
    615     echo -n "Testing coin irregular loss balances... "
    616     check_balance \
    617         "coin_irregular_loss" \
    618         "TESTKUDOS:0" \
    619         "Wrong total bad sig loss from coins"
    620 
    621     echo -n "Testing reserves bad sig loss balances... "
    622     check_balance \
    623         "reserves_total_bad_sig_loss" \
    624         "TESTKUDOS:0" \
    625         "Wrong total bad sig loss from reserves"
    626 
    627     # The aggregator ran and every transfer it decided on was executed, so
    628     # nothing may be left aggregated-but-unpaid, under any of the three
    629     # headings.  This database has no KYC at all (see
    630     # generate-auditor-basedb.sh), so a non-zero total_aml_hold would mean the
    631     # exchange claimed a legal reason it cannot have had; test-kyc.sh covers
    632     # the case where there genuinely is one.
    633     echo -n "Test for withheld payouts... "
    634     check_balance \
    635         "total_aml_hold" \
    636         "TESTKUDOS:0" \
    637         "Auditor found a KYC hold in a database without KYC"
    638     echo -n "Test for aggregates parked below the wire fee... "
    639     check_balance \
    640         "total_small_aggregate" \
    641         "TESTKUDOS:0" \
    642         "Exchange parked an aggregate as too small to pay out"
    643     echo -n "Test for unexplained payout delays... "
    644     check_balance \
    645         "total_transfer_lag" \
    646         "TESTKUDOS:0" \
    647         "Exchange aggregated a payout and did not execute it"
    648 
    649     echo -n "Test for aggregation wire out delta plus... "
    650     check_balance \
    651         "aggregation_total_wire_out_delta_plus" \
    652         "TESTKUDOS:0" \
    653         "Expected total wire out delta plus wrong"
    654 
    655     echo -n "Test for aggregation wire out delta minus... "
    656     check_balance \
    657         "aggregation_total_wire_out_delta_minus" \
    658         "TESTKUDOS:0" \
    659         "Expected total wire out delta minus wrong"
    660 
    661     echo -n "Test for bad incoming delta plus... "
    662     check_balance \
    663         "total_bad_amount_in_plus" \
    664         "TESTKUDOS:0" \
    665         "Expected total wire in delta plus wrong"
    666 
    667     echo -n "Test for bad incoming delta minus... "
    668     check_balance \
    669         "total_bad_amount_in_minus" \
    670         "TESTKUDOS:0" \
    671         "Expected total wire in delta minus wrong"
    672 
    673     echo -n "Test for misattribution amounts... "
    674     check_balance \
    675         "total_misattribution_in" \
    676         "TESTKUDOS:0" \
    677         "Expected total misattribution in wrong"
    678 
    679     echo -n "Checking for unexpected aggregation delta plus differences... "
    680     check_balance \
    681         "aggregation_total_arithmetic_delta_plus" \
    682         "TESTKUDOS:0" \
    683         "Wrong arithmetic delta plus from aggregations"
    684 
    685     echo -n "Checking for unexpected aggregation delta minus differences... "
    686     check_balance \
    687         "aggregation_total_arithmetic_delta_minus" \
    688         "TESTKUDOS:0" \
    689         "Wrong arithmetic delta minus from aggregations"
    690 
    691     echo -n "Checking for unexpected coin delta plus differences... "
    692     check_balance \
    693         "coins_total_arithmetic_delta_plus" \
    694         "TESTKUDOS:0" \
    695         "Wrong arithmetic delta plus from coins"
    696 
    697     echo -n "Checking for unexpected coin delta minus differences... "
    698     check_balance \
    699         "coins_total_arithmetic_delta_minus" \
    700         "TESTKUDOS:0" \
    701         "Wrong arithmetic delta minus from coins"
    702 
    703     echo -n "Checking for unexpected reserves delta plus... "
    704     check_balance \
    705         "reserves_total_arithmetic_delta_plus" \
    706         "TESTKUDOS:0" \
    707         "Wrong arithmetic delta plus from reserves"
    708 
    709     echo -n "Checking for unexpected reserves delta minus... "
    710     check_balance \
    711         "reserves_total_arithmetic_delta_minus" \
    712         "TESTKUDOS:0" \
    713         "Wrong arithmetic delta minus from reserves"
    714 
    715     echo -n "Checking for unexpected wire out differences "
    716     check_no_report "wire-out-inconsistencies"
    717 
    718     # cannot easily undo aggregator, hence full reload
    719     full_reload
    720     cleanup
    721 }
    722 
    723 
    724 # Run without aggregator, hence auditor should detect wire
    725 # transfer lag!
    726 function test_1() {
    727 
    728     echo "===========1: normal run==========="
    729     run_audit
    730     check_auditor_running
    731 
    732     echo "Checking output"
    733     # if an emergency was detected, that is a bug and we should fail
    734 
    735     call_endpoint "balances"
    736 
    737     echo -n "Test for emergencies... "
    738     check_no_report "emergencies"
    739     echo -n "Test for emergencies by count... "
    740     check_no_report "emergencies-by-count"
    741     echo -n "Test for wire inconsistencies... "
    742     check_no_report "denomination-key-validity-withdraw-inconsistencies"
    743 
    744     # TODO: check operation balances are correct (once we have all transaction types and wallet is deterministic)
    745     # TODO: check revenue summaries are correct (once we have all transaction types and wallet is deterministic)
    746 
    747     echo -n "Check for lag detection... "
    748     # Check wire transfer lag reported (no aggregator!)
    749     check_not_balance \
    750         "total_amount_lag" \
    751         "TESTKUDOS:0" \
    752         "Failed to detect lag"
    753 
    754     echo -n "Test for bad incoming delta plus... "
    755     check_balance \
    756         "total_bad_amount_in_plus" \
    757         "TESTKUDOS:0" \
    758         "Expected total wire in delta plus wrong"
    759 
    760     echo -n "Test for bad incoming delta minus... "
    761     check_balance \
    762         "total_bad_amount_in_minus" \
    763         "TESTKUDOS:0" \
    764         "Expected total wire in delta minus wrong"
    765 
    766     echo -n "Test for misattribution amounts... "
    767     check_balance \
    768         "total_misattribution_in" \
    769         "TESTKUDOS:0" \
    770         "Expected total misattribution in wrong"
    771     # Database was unmodified, no need to undo
    772 }
    773 
    774 
    775 # Change amount of wire transfer reported by exchange
    776 function test_2() {
    777 
    778     echo "===========2: reserves_in inconsistency ==========="
    779     echo -n "Modifying database: "
    780     echo "UPDATE exchange.reserves_in SET credit.val=5 WHERE reserve_in_serial_id=1" \
    781         | psql -At "$DB"
    782 
    783     run_audit
    784     check_auditor_running
    785 
    786     echo -n "Testing inconsistency detection ... "
    787     check_report \
    788         "reserve-in-inconsistencies" \
    789         "row_id" 1
    790     echo -n "Testing inconsistency detection amount wired ... "
    791     check_report \
    792         "reserve-in-inconsistencies" \
    793         "amount_wired" "TESTKUDOS:10"
    794     echo -n "Testing inconsistency detection amount expected ... "
    795     check_report \
    796         "reserve-in-inconsistencies" \
    797         "amount_exchange_expected" "TESTKUDOS:5"
    798 
    799     call_endpoint "balances"
    800     echo -n "Checking wire credit balance minus ... "
    801     check_balance \
    802         "total_bad_amount_in_minus" \
    803         "TESTKUDOS:0" \
    804         "Wrong total_bad_amount_in_minus"
    805     echo -n "Checking wire credit balance plus ... "
    806     check_balance \
    807         "total_bad_amount_in_plus" \
    808         "TESTKUDOS:5" \
    809         "Expected total_bad_amount_in_plus wrong"
    810 
    811     echo -n "Undoing database modification "
    812     echo "UPDATE exchange.reserves_in SET credit.val=10 WHERE reserve_in_serial_id=1" \
    813         | psql -Aqt "$DB"
    814     full_reload
    815     cleanup
    816 }
    817 
    818 
    819 # Check for incoming wire transfer amount given being
    820 # lower than what exchange claims to have received.
    821 function test_3() {
    822 
    823     echo "===========3: reserves_in inconsistency==========="
    824     echo "UPDATE exchange.reserves_in SET credit.val=15 WHERE reserve_in_serial_id=1" \
    825         | psql -Aqt "$DB"
    826 
    827     run_audit
    828     check_auditor_running
    829 
    830     echo "Checking reserve balance summary inconsistency detection ..."
    831     check_report \
    832         "reserve-balance-summary-wrong-inconsistencies" \
    833         "auditor_amount" "TESTKUDOS:5.01"
    834     check_report \
    835         "reserve-balance-summary-wrong-inconsistencies" \
    836         "exchange_amount" "TESTKUDOS:0.01"
    837 
    838     call_endpoint "balances"
    839     check_balance \
    840         "reserves_reserve_loss" \
    841         "TESTKUDOS:0" \
    842         "Wrong total loss from insufficient balance"
    843 
    844     echo -n "Testing inconsistency detection ... "
    845     check_report \
    846         "reserve-in-inconsistencies" \
    847         "row_id" 1
    848     echo -n "Testing inconsistency detection amount wired ... "
    849     check_report \
    850         "reserve-in-inconsistencies" \
    851         "amount_wired" "TESTKUDOS:10"
    852     echo -n "Testing inconsistency detection amount expected ... "
    853     check_report \
    854         "reserve-in-inconsistencies" \
    855         "amount_exchange_expected" "TESTKUDOS:15"
    856 
    857     echo -n "Checking wire credit balance minus ... "
    858     check_balance \
    859         "total_bad_amount_in_minus" \
    860         "TESTKUDOS:5" \
    861         "Wrong total_bad_amount_in_minus"
    862     echo -n "Checking wire credit balance plus ... "
    863     check_balance \
    864         "total_bad_amount_in_plus" \
    865         "TESTKUDOS:0" \
    866         "Wrong total_bad_amount_in_plus"
    867 
    868     # Undo database modification
    869     echo "UPDATE exchange.reserves_in SET credit.val=10 WHERE reserve_in_serial_id=1" | psql -Aqt "$DB"
    870     full_reload
    871     cleanup
    872 }
    873 
    874 
    875 # Check for incoming wire transfer amount given being
    876 # lower than what exchange claims to have received.
    877 function test_4() {
    878     echo "===========4: deposit wire target wrong================="
    879 
    880     SERIALE=$(echo "SELECT coin_deposit_serial_id FROM exchange.coin_deposits WHERE (amount_with_fee).val=3 ORDER BY coin_deposit_serial_id LIMIT 1;" | psql "$DB" -Aqt)
    881     OLD_COIN_SIG=$(echo "SELECT coin_sig FROM exchange.coin_deposits WHERE coin_deposit_serial_id=${SERIALE};"  | psql "$DB" -Aqt)
    882     echo -n "Manipulating row ${SERIALE} ..."
    883 # shellcheck disable=SC2028
    884     echo "INSERT INTO exchange.wire_targets (payto_uri, wire_target_h_payto) VALUES ('payto://x-taler-bank/localhost/testuser-xxlargtp', '\x1e8f31936b3cee8f8afd3aac9e38b5db42d45b721ffc4eb1e5b9ddaf1565660b');" \
    885         | psql -Aqt "$DB"
    886 # shellcheck disable=SC2028
    887     echo "UPDATE exchange.coin_deposits SET coin_sig='\x0f29b2ebf3cd1ecbb3e1f2a7888872058fc870c28c0065d4a7d457f2fee9eb5ec376958fc52460c8c540e583be10cf67491a6651a62c1bda68051c62dbe9130c' WHERE coin_deposit_serial_id=${SERIALE}" \
    888         | psql -Aqt "$DB"
    889     echo " DONE"
    890 
    891     run_audit
    892     check_auditor_running
    893 
    894     echo -n "Testing inconsistency detection... "
    895     check_report \
    896         "bad-sig-losses" \
    897         "problem_row_id" "${SERIALE}"
    898     echo -n "Testing loss report... "
    899     check_report \
    900         "bad-sig-losses" \
    901         "loss" "TESTKUDOS:3.02"
    902     echo -n "Testing loss operation attribution... "
    903     check_report \
    904         "bad-sig-losses" \
    905         "operation" "deposit"
    906     echo -n "Testing total coin_irregular_loss balance update... "
    907     check_balance \
    908         "coin_irregular_loss" \
    909         "TESTKUDOS:3.02" \
    910         "wrong total coin_irregular_loss"
    911     # Undo:
    912     echo "UPDATE exchange.coin_deposits SET coin_sig='$OLD_COIN_SIG' WHERE coin_deposit_serial_id=${SERIALE}" | psql -Aqt "$DB"
    913 
    914     full_reload
    915     cleanup
    916 }
    917 
    918 
    919 # Test where h_contract_terms in the deposit table is wrong
    920 # (=> bad signature)
    921 function test_5() {
    922     echo "===========5: deposit contract hash wrong================="
    923     # Modify h_wire hash, so it is inconsistent with 'wire'
    924     CSERIAL=$(echo "SELECT coin_deposit_serial_id FROM exchange.coin_deposits WHERE (amount_with_fee).val=3 ORDER BY coin_deposit_serial_id LIMIT 1;" | psql "$DB" -Aqt)
    925     SERIAL=$(echo "SELECT batch_deposit_serial_id FROM exchange.coin_deposits WHERE (amount_with_fee).val=3 ORDER BY coin_deposit_serial_id LIMIT 1;" | psql "$DB" -Aqt)
    926     OLD_H=$(echo "SELECT h_contract_terms FROM exchange.batch_deposits WHERE batch_deposit_serial_id=$SERIAL;" | psql "$DB" -Aqt)
    927     echo -n "Manipulating row ${SERIAL} ..."
    928 # shellcheck disable=SC2028
    929     echo "UPDATE exchange.batch_deposits SET h_contract_terms='\x12bb676444955c98789f219148aa31899d8c354a63330624d3d143222cf3bb8b8e16f69accd5a8773127059b804c1955696bf551dd7be62719870613332aa8d5' WHERE batch_deposit_serial_id=${SERIAL}" \
    930         | psql -At "$DB"
    931 #
    932     run_audit
    933     check_auditor_running
    934 
    935     echo -n "Checking bad signature detection... "
    936     check_report \
    937         "bad-sig-losses" \
    938         "problem_row_id" "$CSERIAL"
    939     echo -n "Testing loss report... "
    940     check_report \
    941         "bad-sig-losses" \
    942         "loss" "TESTKUDOS:3.02"
    943     echo -n "Testing loss operation attribution... "
    944     check_report \
    945         "bad-sig-losses" \
    946         "operation" "deposit"
    947     echo -n "Testing total coin_irregular_loss balance update... "
    948     check_balance \
    949         "coin_irregular_loss" \
    950         "TESTKUDOS:3.02" \
    951         "wrong total coin_irregular_loss"
    952 
    953     # Undo:
    954     echo "UPDATE exchange.batch_deposits SET h_contract_terms='${OLD_H}' WHERE batch_deposit_serial_id=$SERIAL" \
    955         | psql -Aqt "$DB"
    956 
    957 }
    958 
    959 
    960 # Test where denom_sig in known_coins table is wrong
    961 # (=> bad signature)
    962 function test_6() {
    963     echo "===========6: known_coins signature wrong================="
    964     # Modify denom_sig, so it is wrong
    965     OLD_ROW=$(echo "SELECT known_coin_id FROM exchange.known_coins LIMIT 1;" | psql "$DB" -Aqt)
    966     OLD_SIG=$(echo "SELECT denom_sig FROM exchange.known_coins WHERE known_coin_id=$OLD_ROW;" | psql "$DB" -Aqt)
    967     COIN_PUB=$(echo "SELECT coin_pub FROM exchange.known_coins WHERE denom_sig='$OLD_SIG';"  | psql "$DB" -Aqt)
    968 # shellcheck disable=SC2028
    969     echo "UPDATE exchange.known_coins SET denom_sig='\x0000000100000000287369672d76616c200a2028727361200a2020287320233542383731423743393036444643303442424430453039353246413642464132463537303139374131313437353746324632323332394644443146324643333445393939413336363430334233413133324444464239413833353833464536354442374335434445304441453035374438363336434541423834463843323843344446304144363030343430413038353435363039373833434431333239393736423642433437313041324632414132414435413833303432434346314139464635394244434346374436323238344143354544364131373739463430353032323241373838423837363535453434423145443831364244353638303232413123290a2020290a20290b' WHERE coin_pub='$COIN_PUB'" \
    970         | psql -Aqt "$DB"
    971 
    972     run_audit
    973     check_auditor_running
    974 
    975     echo -n "Checking bad-signature-loss detected ..."
    976     check_row \
    977         "bad-sig-losses" \
    978         "problem_row_id" "1" # Row reported is that of deposits or melt table, not known_coins
    979     echo -n "Checking bad-signature-loss amount detected ..."
    980     check_report_neg \
    981         "bad-sig-losses" \
    982         "loss" "TESTKUDOS:0"
    983     echo -n "Checking bad-signature-loss operation detected ..."
    984     # The coin was both melted and deposited, so the bad denomination
    985     # signature is reported against either operation; only require that
    986     # the deposit was flagged.
    987     check_report_any \
    988         "bad-sig-losses" \
    989         "operation" "deposit"
    990     echo -n "Checking bad-signature-loss balance update ..."
    991     check_not_balance \
    992         "coin_irregular_loss" \
    993         "TESTKUDOS:0" \
    994         "Wrong total bad sig loss"
    995 
    996     echo -n "Undo database change ... "
    997     echo "UPDATE exchange.known_coins SET denom_sig='$OLD_SIG' WHERE coin_pub='$COIN_PUB'" | psql -Aqt "$DB"
    998     full_reload
    999     cleanup
   1000 }
   1001 
   1002 
   1003 # Test where signature in the withdraw table is wrong
   1004 function test_7() {
   1005     echo "===========7: withdraw signature wrong================="
   1006     # Modify reserve_sig, so it is bogus
   1007     HBE=$(echo 'SELECT withdraw_id FROM exchange.withdraw LIMIT 1;' | psql "$DB" -Aqt)
   1008     OLD_SIG=$(echo "SELECT reserve_sig FROM exchange.withdraw WHERE withdraw_id='$HBE';" | psql "$DB" -Aqt)
   1009     A_VAL=$(echo "SELECT (amount_with_fee).val FROM exchange.withdraw WHERE withdraw_id='$HBE';" | psql "$DB" -Aqt)
   1010     A_FRAC=$(echo "SELECT (amount_with_fee).frac FROM exchange.withdraw WHERE withdraw_id='$HBE';" | psql "$DB" -Aqt)
   1011     # Normalize, we only deal with cents in this test-case
   1012     A_FRAC=$(( A_FRAC / 1000000))
   1013     # shellcheck disable=SC2028
   1014     echo "UPDATE exchange.withdraw SET reserve_sig='\x9ef381a84aff252646a157d88eded50f708b2c52b7120d5a232a5b628f9ced6d497e6652d986b581188fb014ca857fd5e765a8ccc4eb7e2ce9edcde39accaa4b' WHERE withdraw_id='$HBE'" \
   1015         | psql -Aqt "$DB"
   1016     run_audit
   1017     check_auditor_running
   1018 
   1019     echo -n "Checking bad signature was detected ..."
   1020     check_report \
   1021         "bad-sig-losses" \
   1022         "operation" "withdraw"
   1023     echo -n "Checking loss was reported ..."
   1024     if [ "$A_FRAC" != 0 ]
   1025     then
   1026         if [ "$A_FRAC" -lt 10 ]
   1027         then
   1028             A_PREV="0"
   1029         else
   1030             A_PREV=""
   1031         fi
   1032         EXPECTED_LOSS="TESTKUDOS:$A_VAL.$A_PREV$A_FRAC"
   1033     else
   1034         EXPECTED_LOSS="TESTKUDOS:$A_VAL"
   1035     fi
   1036     check_report \
   1037         "bad-sig-losses" \
   1038         "loss" "$EXPECTED_LOSS"
   1039     echo "Checking loss was totaled up ..."
   1040     check_balance \
   1041         "reserves_total_bad_sig_loss" \
   1042         "$EXPECTED_LOSS" \
   1043         "wrong total bad sig loss"
   1044 
   1045     # Undo:
   1046     echo "UPDATE exchange.withdraw SET reserve_sig='$OLD_SIG' WHERE withdraw_id='$HBE'" | psql -Aqt "$DB"
   1047     full_reload
   1048     cleanup
   1049 }
   1050 
   1051 
   1052 # Test wire transfer subject disagreement!
   1053 function test_8() {
   1054 
   1055     echo "===========8: wire-transfer-subject disagreement==========="
   1056     # Technically, this call shouldn't be needed, as libeufin should already be stopped here.
   1057     stop_libeufin
   1058     OLD_ID=$(echo "SELECT exchange_incoming_id FROM libeufin_bank.taler_exchange_incoming JOIN libeufin_bank.bank_account_transactions ON (bank_transaction=bank_transaction_id) WHERE (amount).val=10 ORDER BY exchange_incoming_id LIMIT 1;" | psql "${DB}" -Aqt) \
   1059         || exit_fail "Failed to SELECT FROM libeufin_bank.bank_account_transactions!"
   1060     OLD_WTID=$(echo "SELECT metadata FROM libeufin_bank.taler_exchange_incoming WHERE exchange_incoming_id='$OLD_ID';" \
   1061                    | psql "${DB}" -Aqt)
   1062     NEW_WTID="\x77b4e23a41a0158299cdbe4d3247b42f907836d76dbc45c585c6a9beb196e6ca"
   1063     echo -n "Modifying $OLD_ID ..."
   1064     echo "UPDATE libeufin_bank.taler_exchange_incoming SET metadata='$NEW_WTID' WHERE exchange_incoming_id='$OLD_ID';" \
   1065         | psql "${DB}" -At \
   1066         || exit_fail "Failed to update taler_exchange_incoming"
   1067     echo "DONE"
   1068 
   1069     run_audit
   1070     check_auditor_running
   1071 
   1072     echo -n "Checking inconsistency diagnostic ..."
   1073     check_report \
   1074         "reserve-in-inconsistencies" \
   1075         "diagnostic" "wire subject does not match"
   1076     echo -n "Checking expected balance report ..."
   1077     check_report \
   1078         "reserve-in-inconsistencies" \
   1079         "amount_exchange_expected" "TESTKUDOS:10"
   1080     echo -n "Checking actual incoming balance report ..."
   1081     check_report \
   1082         "reserve-in-inconsistencies" \
   1083         "amount_wired" "TESTKUDOS:0"
   1084     echo -n "Checking balance update (bad plus)..."
   1085     check_balance \
   1086         "total_bad_amount_in_plus" \
   1087         "TESTKUDOS:10" \
   1088         "Wrong total_bad_amount_in_plus"
   1089     echo -n "Checking balance update (bad minus)..."
   1090     check_balance \
   1091         "total_bad_amount_in_minus" \
   1092         "TESTKUDOS:10" \
   1093         "Wrong total_bad_amount_in_plus"
   1094 
   1095     # Undo database modification
   1096     echo "UPDATE libeufin_bank.taler_exchange_incoming SET metadata='$OLD_WTID' WHERE exchange_incoming_id='$OLD_ID';" \
   1097         | psql "${DB}" -q
   1098     full_reload
   1099     cleanup
   1100 }
   1101 
   1102 
   1103 # Test wire origin disagreement!
   1104 function test_9() {
   1105 
   1106     echo "===========9: wire-origin disagreement==========="
   1107     # Technically, this call shouldn't be needed, as libeufin should already be stopped here.
   1108     stop_libeufin
   1109     OLD_ID=$(echo "SELECT bank_transaction FROM libeufin_bank.taler_exchange_incoming JOIN libeufin_bank.bank_account_transactions ON (bank_transaction=bank_transaction_id) WHERE (amount).val=10 ORDER BY bank_transaction LIMIT 1;" | psql "${DB}" -Aqt) \
   1110         || exit_fail "Failed to SELECT FROM libeufin_bank.bank_account_transactions!"
   1111     OLD_ACC=$(echo "SELECT debtor_payto FROM libeufin_bank.bank_account_transactions WHERE bank_transaction_id='$OLD_ID';" | psql "${DB}" -Aqt)
   1112 
   1113     echo -n "Modifying $OLD_ID ..."
   1114     echo "UPDATE libeufin_bank.bank_account_transactions SET debtor_payto='payto://iban/DE68210501700012345678' WHERE bank_transaction_id='$OLD_ID';" \
   1115         | psql "${DB}" -At
   1116 
   1117     run_audit
   1118     check_auditor_running
   1119 
   1120     echo -n "Testing inconsistency detection... "
   1121     check_report \
   1122         misattribution-in-inconsistencies \
   1123         "amount" "TESTKUDOS:10"
   1124     echo -n "Testing balance update... "
   1125     check_balance \
   1126         "total_misattribution_in" \
   1127         "TESTKUDOS:10" \
   1128         "Reported total_misattribution_in wrong"
   1129     # Undo database modification
   1130     echo "UPDATE libeufin_bank.bank_account_transactions SET debtor_payto='$OLD_ACC' WHERE bank_transaction_id='$OLD_ID';" \
   1131         | psql "${DB}" -Atq
   1132     full_reload
   1133     cleanup
   1134 }
   1135 
   1136 
   1137 # Test wire_in timestamp disagreement!
   1138 function test_10() {
   1139     NOW_MS=$(date +%s)000
   1140     echo "===========10: wire-timestamp disagreement==========="
   1141     # Technically, this call shouldn't be needed, as libeufin should already be stopped here.
   1142     stop_libeufin
   1143     OLD_ID=$(echo "SELECT bank_transaction FROM libeufin_bank.taler_exchange_incoming JOIN libeufin_bank.bank_account_transactions ON (bank_transaction=bank_transaction_id) WHERE (amount).val=10 ORDER BY exchange_incoming_id LIMIT 1;" | psql "${DB}" -Aqt) \
   1144         || exit_fail "Failed to SELECT FROM libeufin_bank.bank_account_transactions!"
   1145     OLD_DATE=$(echo "SELECT transaction_date FROM libeufin_bank.bank_account_transactions WHERE bank_transaction_id='$OLD_ID';" | psql "${DB}" -Aqt)
   1146     echo -n "Modifying $OLD_ID ..."
   1147     echo "UPDATE libeufin_bank.bank_account_transactions SET transaction_date=$NOW_MS WHERE bank_transaction_id=$OLD_ID;" \
   1148         | psql "${DB}" -At
   1149 
   1150     run_audit
   1151     check_auditor_running
   1152 
   1153     echo -n "Testing inconsistency detection diagnostic... "
   1154     check_report \
   1155         row-minor-inconsistencies \
   1156         "diagnostic" "execution date mismatch"
   1157     echo -n "Testing inconsistency detection table... "
   1158     check_report \
   1159         row-minor-inconsistencies \
   1160         "row_table" "reserves_in"
   1161     # Undo database modification
   1162     echo "UPDATE libeufin_bank.bank_account_transactions SET transaction_date=$OLD_DATE WHERE bank_transaction_id=$OLD_ID;" \
   1163         | psql "${DB}" -Aqt
   1164     full_reload
   1165     cleanup
   1166 }
   1167 
   1168 
   1169 # Test for extra outgoing wire transfer.
   1170 function test_11() {
   1171     echo "===========11: spurious outgoing transfer ==========="
   1172     # Technically, this call shouldn't be needed, as libeufin should already be stopped here.
   1173     stop_libeufin
   1174     launch_libeufin
   1175     OTHER_IBAN=$(echo "SELECT internal_payto FROM libeufin_bank.bank_accounts ba JOIN libeufin_bank.customers bc ON (ba.owning_customer_id = bc.customer_id) WHERE username='fortytwo'" | psql "${DB}" -Aqt)
   1176 
   1177     await_bank
   1178     echo -n "Creating bogus transfer... "
   1179     STATUS=$(curl -H "Content-Type: application/json" -X POST \
   1180       -u 'exchange:password' \
   1181       http://localhost:8082/accounts/exchange/taler-wire-gateway/transfer \
   1182       -d '{"credit_account":"'"$OTHER_IBAN"'","exchange_base_url":"http://exchange.example.com/","amount":"TESTKUDOS:10","wtid":"7X93HVKPHE0KAQ6KHSB3921KJGSVDMQFHMQV17885YJDMZ20XS9G","request_uid":"7X93HKPHE0KAQ6KHSB3921KJGSVDMQFHMQV17885YJDMZ20XS9G7X93HVKPHE0KAQ6KHSB3921KJGSVDMQFHMQV17885YJDMZ20XS9G"}' \
   1183       -w "%{http_code}" -s -o /dev/null)
   1184 
   1185     if [ "$STATUS" != "200" ]
   1186     then
   1187         exit_fail "Expected 200 OK. Got: $STATUS"
   1188     fi
   1189     echo "DONE"
   1190     stop_libeufin
   1191 
   1192     run_audit
   1193     check_auditor_running
   1194 
   1195     echo -n "Testing inconsistency detection... "
   1196     check_report \
   1197         "wire-out-inconsistencies" \
   1198         "claimed" \
   1199         "TESTKUDOS:10"
   1200     echo -n "Testing bad_amount_plus balance reporting... "
   1201     check_balance \
   1202         "total_bad_amount_out_plus" \
   1203         "TESTKUDOS:10" \
   1204         "reported total_bad_amount_plus wrong"
   1205     echo -n "Testing bad_amount_minus balance reporting... "
   1206     check_balance \
   1207         "total_bad_amount_out_minus" \
   1208         "TESTKUDOS:0" \
   1209         "reported total_bad_amount_minus wrong"
   1210     echo -n "Testing expected amount is correct... "
   1211     check_report \
   1212         "wire-out-inconsistencies" \
   1213         "expected" \
   1214         "TESTKUDOS:0"
   1215     echo -n "Testing diagnostic message is correct... "
   1216     check_report \
   1217         "wire-out-inconsistencies" \
   1218         "diagnostic" \
   1219         "missing justification for outgoing wire transfer"
   1220     full_reload
   1221 }
   1222 
   1223 
   1224 function test_12() {
   1225 
   1226     echo "===========12: normal run with aggregator and profit drain==========="
   1227     run_audit aggregator drain
   1228     check_auditor_running
   1229 
   1230     echo "Checking output"
   1231     # if an emergency was detected, that is a bug and we should fail
   1232     echo -n "Test for emergencies... "
   1233     check_no_report "emergencies"
   1234     echo -n "Test for deposit confirmation detection... "
   1235     check_no_report "deposit-confirmations"
   1236     echo -n "Test for emergencies by count... "
   1237     check_no_report "emergencies-by-count"
   1238 
   1239     echo -n "Testing bad sig loss balance... "
   1240     check_balance \
   1241         "aggregation_total_bad_sig_loss" \
   1242         "TESTKUDOS:0" \
   1243         "Wrong total bad sig loss from aggregation, got unexpected loss"
   1244 
   1245     echo -n "Testing coin irregular loss balances... "
   1246     check_balance \
   1247         "coin_irregular_loss" \
   1248         "TESTKUDOS:0" \
   1249         "Wrong total bad sig loss from coins"
   1250 
   1251     echo -n "Testing reserves bad sig loss balances... "
   1252     check_balance \
   1253         "reserves_total_bad_sig_loss" \
   1254         "TESTKUDOS:0" \
   1255         "Wrong total bad sig loss from reserves"
   1256 
   1257     echo -n "Test for aggregation wire out delta plus... "
   1258     check_balance \
   1259         "aggregation_total_wire_out_delta_plus" \
   1260         "TESTKUDOS:0" \
   1261         "Expected total wire out delta plus wrong"
   1262 
   1263     echo -n "Test for aggregation wire out delta minus... "
   1264     check_balance \
   1265         "aggregation_total_wire_out_delta_minus" \
   1266         "TESTKUDOS:0" \
   1267         "Expected total wire out delta minus wrong"
   1268 
   1269     echo -n "Test for bad incoming delta plus... "
   1270     check_balance \
   1271         "total_bad_amount_in_plus" \
   1272         "TESTKUDOS:0" \
   1273         "Expected total wire in delta plus wrong"
   1274 
   1275     echo -n "Test for total misattribution in ... "
   1276     check_balance \
   1277         "total_misattribution_in" \
   1278         "TESTKUDOS:0" \
   1279         "Expected total wire in delta plus wrong"
   1280 
   1281     echo -n "Test for bad incoming delta minus... "
   1282     check_balance \
   1283         "total_bad_amount_in_minus" \
   1284         "TESTKUDOS:0" \
   1285         "Expected total wire in delta minus wrong"
   1286 
   1287     echo -n "Test for bad outgoing delta plus... "
   1288     check_balance \
   1289         "total_bad_amount_out_plus" \
   1290         "TESTKUDOS:0" \
   1291         "Expected total wire out delta plus wrong"
   1292 
   1293     echo -n "Test for bad outgoing delta minus... "
   1294     check_balance \
   1295         "total_bad_amount_out_minus" \
   1296         "TESTKUDOS:0" \
   1297         "Expected total wire in delta minus wrong"
   1298 
   1299     echo -n "Test for misattribution amounts... "
   1300     check_balance \
   1301         "total_misattribution_in" \
   1302         "TESTKUDOS:0" \
   1303         "Expected total misattribution in wrong"
   1304 
   1305     echo -n "Checking for unexpected aggregation delta plus differences... "
   1306     check_balance \
   1307         "aggregation_total_arithmetic_delta_plus" \
   1308         "TESTKUDOS:0" \
   1309         "Wrong arithmetic delta plus from aggregations"
   1310 
   1311     echo -n "Checking for unexpected aggregation delta minus differences... "
   1312     check_balance \
   1313         "aggregation_total_arithmetic_delta_minus" \
   1314         "TESTKUDOS:0" \
   1315         "Wrong arithmetic delta minus from aggregations"
   1316 
   1317     echo -n "Checking for unexpected coin delta plus differences... "
   1318     check_balance \
   1319         "coins_total_arithmetic_delta_plus" \
   1320         "TESTKUDOS:0" \
   1321         "Wrong arithmetic delta plus from coins"
   1322 
   1323     echo -n "Checking for unexpected coin delta minus differences... "
   1324     check_balance \
   1325         "coins_total_arithmetic_delta_minus" \
   1326         "TESTKUDOS:0" \
   1327         "Wrong arithmetic delta minus from coins"
   1328 
   1329     echo -n "Checking for unexpected reserves delta plus... "
   1330     check_balance \
   1331         "reserves_total_arithmetic_delta_plus" \
   1332         "TESTKUDOS:0" \
   1333         "Wrong arithmetic delta plus from reserves"
   1334 
   1335     echo -n "Checking for unexpected reserves delta minus... "
   1336     check_balance \
   1337         "reserves_total_arithmetic_delta_minus" \
   1338         "TESTKUDOS:0" \
   1339         "Wrong arithmetic delta minus from reserves"
   1340 
   1341     echo -n "Checking for unexpected wire out differences... "
   1342     check_no_report "wire-out-inconsistencies"
   1343 
   1344     # Just to test the endpoint and for logging ...
   1345     call_endpoint "balances"
   1346 
   1347     echo -n "Testing for aggregation bad sig loss... "
   1348     check_balance \
   1349         "aggregation_total_bad_sig_loss" \
   1350         "TESTKUDOS:0" \
   1351         "Wrong total bad sig loss from aggregation, got unexpected loss"
   1352 
   1353     echo -n "Testing for coin bad sig loss... "
   1354     check_balance \
   1355         "coin_irregular_loss" \
   1356         "TESTKUDOS:0" \
   1357         "Wrong total bad sig loss from coins, got unexpected loss"
   1358 
   1359     echo -n "Testing for reserves bad sig loss... "
   1360     check_balance \
   1361         "reserves_total_bad_sig_loss" \
   1362         "TESTKUDOS:0" \
   1363         "Wrong total bad sig loss from reserves, got unexpected loss"
   1364 
   1365     echo -n "Checking for unexpected aggregation delta plus differences... "
   1366     check_balance \
   1367         "aggregation_total_arithmetic_delta_plus" \
   1368         "TESTKUDOS:0" \
   1369         "Wrong arithmetic delta plus from aggregations"
   1370 
   1371     echo -n "Checking for unexpected aggregation delta minus differences... "
   1372     check_balance \
   1373         "aggregation_total_arithmetic_delta_minus" \
   1374         "TESTKUDOS:0" \
   1375         "Wrong arithmetic delta minus from aggregations"
   1376 
   1377     echo -n "Checking for unexpected coin delta plus differences... "
   1378     check_balance \
   1379         "coins_total_arithmetic_delta_plus" \
   1380         "TESTKUDOS:0" \
   1381         "Wrong arithmetic delta plus from coins"
   1382 
   1383     echo -n "Checking for unexpected coin delta minus differences... "
   1384     check_balance \
   1385         "coins_total_arithmetic_delta_minus" \
   1386         "TESTKUDOS:0" \
   1387         "Wrong arithmetic delta minus from coins"
   1388 
   1389     echo -n "Checking for unexpected reserves delta plus... "
   1390     check_balance \
   1391         "reserves_total_arithmetic_delta_plus" \
   1392         "TESTKUDOS:0" \
   1393         "Wrong arithmetic delta plus from reserves"
   1394 
   1395     echo -n "Checking for unexpected reserves delta minus... "
   1396     check_balance \
   1397         "reserves_total_arithmetic_delta_minus" \
   1398         "TESTKUDOS:0" \
   1399         "Wrong arithmetic delta minus from reserves"
   1400 
   1401     echo -n "Checking amount arithmetic inconsistency"
   1402     check_no_report "amount-arithmetic-inconsistencies"
   1403 
   1404     echo -n "Checking for unexpected wire out differences "
   1405     check_no_report "wire-out-inconsistencies"
   1406 
   1407     echo -n "Checking total drained... "
   1408     check_balance \
   1409         "total_drained" \
   1410         "TESTKUDOS:0.1" \
   1411         "Wrong total drained amount reported"
   1412     # cannot easily undo aggregator, hence full reload
   1413     full_reload
   1414 }
   1415 
   1416 
   1417 # Test for wrong signature on refresh.
   1418 function test_13() {
   1419 
   1420     echo "===========13: wrong melt signature ==========="
   1421     # Modify denom_sig, so it is wrong
   1422     COIN_PUB=$(echo "SELECT old_coin_pub FROM exchange.refresh LIMIT 1;"  | psql "$DB" -Aqt)
   1423     OLD_SIG=$(echo "SELECT old_coin_sig FROM exchange.refresh WHERE old_coin_pub='$COIN_PUB';" | psql "$DB" -Aqt)
   1424     NEW_SIG="\xba588af7c13c477dca1ac458f65cc484db8fba53b969b873f4353ecbd815e6b4c03f42c0cb63a2b609c2d726e612fd8e0c084906a41f409b6a23a08a83c89a02"
   1425     echo "UPDATE exchange.refresh SET old_coin_sig='$NEW_SIG' WHERE old_coin_pub='$COIN_PUB'" \
   1426         | psql -Aqt "$DB"
   1427 
   1428     run_audit
   1429     check_auditor_running
   1430 
   1431     echo -n "Testing inconsistency detection... "
   1432 
   1433     check_report \
   1434         "bad-sig-losses" \
   1435         "operation" "melt"
   1436     echo -n "Checking loss amount reported ..."
   1437     check_report \
   1438         "bad-sig-losses" \
   1439         "loss" "TESTKUDOS:3.96"
   1440     echo -n "Checking loss amount totaled ..."
   1441     check_balance \
   1442         "coin_irregular_loss" \
   1443         "TESTKUDOS:3.96" \
   1444         "Loss inconsistent"
   1445 
   1446     # cannot easily undo DELETE, hence full reload
   1447     full_reload
   1448 }
   1449 
   1450 
   1451 # Test for wire fee disagreement
   1452 function test_14() {
   1453 
   1454     echo "===========14: wire-fee disagreement==========="
   1455 
   1456     # Wire fees are only checked/generated once there are
   1457     # actual outgoing wire transfers, so we need to run the
   1458     # aggregator here.
   1459     pre_audit aggregator
   1460     echo "UPDATE exchange.wire_fee SET wire_fee.frac=100 WHERE wire_fee_serial=1;" \
   1461         | psql -Aqt "$DB"
   1462     audit_only
   1463     post_audit
   1464     check_auditor_running
   1465 
   1466     echo -n "Checking wire-fee inconsistency was detected ..."
   1467     check_report \
   1468         "row-inconsistencies" \
   1469         "row_table" "wire-fee"
   1470     echo -n "Checking diagnostic was set correctly ..."
   1471     check_report \
   1472         "row-inconsistencies" \
   1473         "diagnostic" "wire fee signature invalid at given time"
   1474 
   1475     # cannot easily undo aggregator, hence full reload
   1476     full_reload
   1477 }
   1478 
   1479 
   1480 # Test where salt in the deposit table is wrong
   1481 function test_15() {
   1482     echo "===========15: deposit wire salt wrong================="
   1483 
   1484     # Modify wire_salt hash, so it is inconsistent
   1485     ##SALT=$(echo "SELECT wire_salt FROM exchange.deposits WHERE deposit_serial_id=1;" | psql -Aqt "$DB")
   1486     SALT=$(echo "SELECT wire_salt FROM exchange.batch_deposits WHERE batch_deposit_serial_id=1;" | psql -Aqt "$DB")
   1487 # shellcheck disable=SC2028
   1488     echo "UPDATE exchange.batch_deposits SET wire_salt='\x1197cd7f7b0e13ab1905fedb36c536a2' WHERE batch_deposit_serial_id=1;" \
   1489         | psql -Aqt "$DB"
   1490 
   1491     run_audit
   1492     check_auditor_running
   1493 
   1494     echo -n "Checking broken deposit signature detected ..."
   1495     check_report \
   1496         "bad-sig-losses" \
   1497         "operation" "deposit"
   1498 
   1499     # Restore DB
   1500     echo "UPDATE exchange.batch_deposits SET wire_salt='$SALT' WHERE batch_deposit_serial_id=1;" \
   1501         | psql -Aqt "$DB"
   1502     stop_auditor_httpd
   1503 
   1504 }
   1505 
   1506 
   1507 # Test where wired amount (wire out) is wrong
   1508 function test_16() {
   1509     echo "===========16: incorrect wire_out amount================="
   1510 
   1511     # First, we need to run the aggregator so we even
   1512     # have a wire_out to modify.
   1513     pre_audit aggregator
   1514     check_auditor_running
   1515     stop_libeufin
   1516     OLD_AMOUNT_VAL=$(echo "SELECT (amount).val FROM libeufin_bank.bank_account_transactions WHERE debtor_name='Exchange Company' AND direction='debit';" | psql "${DB}" -Aqt)
   1517     OLD_AMOUNT_FRAC=$(echo "SELECT (amount).frac FROM libeufin_bank.bank_account_transactions WHERE debtor_name='Exchange Company' AND direction='debit';" | psql "${DB}" -Aqt)
   1518     if [[ 0 = "$OLD_AMOUNT_FRAC" ]]
   1519     then
   1520         OLD_AMOUNT="TESTKUDOS:${OLD_AMOUNT_VAL}"
   1521     else
   1522         OLD_AMOUNT_CENTS=$(($OLD_AMOUNT_FRAC / 1000000))
   1523         if [[ 10 -gt "$OLD_AMOUNT_CENTS" ]]
   1524         then
   1525             OLD_AMOUNT="TESTKUDOS:${OLD_AMOUNT_VAL}.0${OLD_AMOUNT_CENTS}"
   1526         else
   1527             OLD_AMOUNT="TESTKUDOS:${OLD_AMOUNT_VAL}.${OLD_AMOUNT_CENTS}"
   1528         fi
   1529     fi
   1530     NEW_AMOUNT="TESTKUDOS:50"
   1531     echo "UPDATE libeufin_bank.bank_account_transactions SET amount=(50,0) WHERE debtor_name='Exchange Company';" \
   1532         | psql "${DB}" -q
   1533     launch_libeufin
   1534     await_bank
   1535 
   1536     audit_only
   1537     check_auditor_running
   1538 
   1539     echo -n "Testing wire-out-inconsistency-expected... "
   1540     check_report \
   1541         "wire-out-inconsistencies" \
   1542         "expected" \
   1543         "$OLD_AMOUNT"
   1544     echo -n "Testing wire-out-inconsistency-claimed... "
   1545     check_report \
   1546         "wire-out-inconsistencies" \
   1547         "claimed" \
   1548         "$NEW_AMOUNT"
   1549     echo -n "Testing bad_amount_minus balance reporting... "
   1550     check_balance \
   1551         "total_bad_amount_out_minus" \
   1552         "TESTKUDOS:0" \
   1553         "reported total_bad_amount_minus wrong"
   1554     echo -n "Testing bad_amount_plus balance reporting... "
   1555     check_not_balance \
   1556         "total_bad_amount_out_plus" \
   1557         "TESTKUDOS:0" \
   1558         "reported total_bad_amount_plus wrong"
   1559 
   1560     stop_libeufin
   1561     echo "Second modification: wire nothing"
   1562     NEW_AMOUNT="TESTKUDOS:0"
   1563     echo "UPDATE libeufin_bank.bank_account_transactions SET amount=(0,0) WHERE debtor_name='Exchange Company';" \
   1564         | psql "${DB}" -q
   1565     launch_libeufin
   1566     audit_only
   1567     stop_libeufin
   1568 
   1569     echo -n "Testing wire-out-inconsistency-expected... "
   1570     check_report \
   1571         "wire-out-inconsistencies" \
   1572         "expected" \
   1573         "$OLD_AMOUNT"
   1574     echo -n "Testing wire-out-inconsistency-claimed... "
   1575     check_report \
   1576         "wire-out-inconsistencies" \
   1577         "claimed" \
   1578         "$NEW_AMOUNT"
   1579     echo -n "Testing bad_amount_minus balance reporting... "
   1580     check_balance \
   1581         "total_bad_amount_out_minus" \
   1582         "$OLD_AMOUNT" \
   1583         "reported total_bad_amount_minus wrong"
   1584     echo -n "Testing bad_amount_plus balance reporting... "
   1585     check_balance \
   1586         "total_bad_amount_out_plus" \
   1587         "TESTKUDOS:0" \
   1588         "reported total_bad_amount_plus wrong"
   1589 
   1590     post_audit
   1591 
   1592     # cannot easily undo aggregator, hence full reload
   1593     full_reload
   1594 }
   1595 
   1596 
   1597 # Test where wire-out timestamp is wrong
   1598 function test_17() {
   1599     echo "===========17: incorrect wire_out timestamp================="
   1600 
   1601     # First, we need to run the aggregator so we even
   1602     # have a wire_out to modify.
   1603     pre_audit aggregator
   1604     stop_libeufin
   1605 
   1606     echo -n "Modifying timestamp of existing wire_out transaction... "
   1607     OLD_DATE=$(echo "SELECT transaction_date FROM libeufin_bank.bank_account_transactions WHERE debtor_name='Exchange Company' AND direction='debit';" | psql "${DB}" -Aqt)
   1608     # Note: need - interval '1h' as "NOW()" may otherwise be exactly what is already in the DB
   1609     # (due to rounding, if this machine is fast...)
   1610     NOW_1HR=$(( $(date +%s) - 3600))
   1611 
   1612     echo "UPDATE libeufin_bank.bank_account_transactions SET transaction_date='${NOW_1HR}000000' WHERE debtor_name='Exchange Company';" \
   1613         | psql "${DB}" -q
   1614     echo "DONE"
   1615 
   1616     launch_libeufin
   1617     await_bank
   1618     audit_only
   1619     post_audit
   1620     check_auditor_running
   1621 
   1622     echo -n "Testing inconsistency detection... "
   1623     check_report \
   1624         row-minor-inconsistencies \
   1625         "row_table" "wire_out"
   1626 
   1627     echo -n "Testing inconsistency diagnostic... "
   1628     call_endpoint "row-minor-inconsistencies"
   1629     DIAG=$(jq -r .records[0].diagnostic < "${MY_TMP_DIR}/row-minor-inconsistencies.json" | awk '{print $1 " " $2 " " $3}')
   1630     if [ "$DIAG" != "execution date mismatch" ]
   1631     then
   1632         exit_fail "Reported diagnostic wrong: $DIAG"
   1633     fi
   1634     echo "PASS"
   1635 
   1636     # cannot easily undo aggregator, hence full reload
   1637     full_reload
   1638 }
   1639 
   1640 
   1641 # Test where we trigger an emergency.
   1642 function test_18() {
   1643     echo "===========18: emergency================="
   1644 
   1645     echo "DELETE FROM exchange.withdraw;" \
   1646         | psql -Aqt "$DB" -q
   1647 
   1648     run_audit
   1649     check_auditor_running
   1650 
   1651     echo -n "Testing bad reserve balance summary reporting ... "
   1652     # note: we check "suppressed" to only check the *existence* here.
   1653     check_report \
   1654         "reserve-balance-summary-wrong-inconsistencies" \
   1655         "suppressed" "false"
   1656     echo -n "Testing emergency detection... "
   1657     check_report \
   1658         "emergencies" \
   1659         "suppressed" "false"
   1660     echo -n "Testing emergency detection by count... "
   1661     check_report \
   1662         "emergencies-by-count" \
   1663         "suppressed" "false"
   1664     echo -n "Testing escrow balance calculation impossibility... "
   1665     check_report \
   1666         "amount-arithmetic-inconsistencies" \
   1667         "suppressed" "false"
   1668     echo -n "Testing loss calculation by count... "
   1669     check_not_balance \
   1670         "coins_emergencies_loss_by_count" \
   1671         "TESTKUDOS:0" \
   1672         "Emergency by count loss not reported"
   1673     echo -n "Testing loss calculation... "
   1674     check_not_balance \
   1675         "coins_emergencies_loss" \
   1676         "TESTKUDOS:0" \
   1677         "Emergency loss not reported"
   1678     # cannot easily undo broad DELETE operation, hence full reload
   1679     full_reload
   1680 }
   1681 
   1682 
   1683 # Test where reserve closure was done properly
   1684 function test_19() {
   1685     echo "===========19: reserve closure done properly ================="
   1686 
   1687     OLD_TIME=$(echo "SELECT execution_date FROM exchange.reserves_in WHERE reserve_in_serial_id=1;" | psql "$DB" -Aqt)
   1688     OLD_VAL=$(echo "SELECT (credit).val FROM exchange.reserves_in WHERE reserve_in_serial_id=1;" | psql "$DB" -Aqt)
   1689     RES_PUB=$(echo "SELECT reserve_pub FROM exchange.reserves_in WHERE reserve_in_serial_id=1;" | psql "$DB" -Aqt)
   1690     OLD_EXP=$(echo "SELECT expiration_date FROM exchange.reserves WHERE reserve_pub='${RES_PUB}';" | psql "$DB" -Aqt)
   1691     VAL_DELTA=1
   1692     NEW_TIME=$(( OLD_TIME - 3024000000000))  # 5 weeks
   1693     NEW_EXP=$(( OLD_EXP - 3024000000000))  # 5 weeks
   1694     NEW_CREDIT=$(( OLD_VAL + VAL_DELTA))
   1695     echo "UPDATE exchange.reserves_in SET execution_date='${NEW_TIME}',credit.val=${NEW_CREDIT} WHERE reserve_in_serial_id=1;" \
   1696         | psql -Aqt "$DB"
   1697     echo "UPDATE exchange.reserves SET current_balance.val=${VAL_DELTA}+(current_balance).val,expiration_date='${NEW_EXP}' WHERE reserve_pub='${RES_PUB}';" \
   1698         | psql -Aqt "$DB"
   1699     # Need to run with the aggregator so the reserve closure happens
   1700     run_audit aggregator
   1701     check_auditor_running
   1702 
   1703     echo -n "Testing reserve closure was done correctly... "
   1704     check_no_report "reserve-not-closed-inconsistencies"
   1705     echo -n "Testing no bogus transfers detected... "
   1706     check_no_report "wire-out-inconsistencies"
   1707 
   1708     # cannot easily undo aggregator, hence full reload
   1709     full_reload
   1710 }
   1711 
   1712 
   1713 # Test where reserve closure was not done properly
   1714 function test_20() {
   1715     echo "===========20: reserve closure missing ================="
   1716 
   1717     OLD_TIME=$(echo "SELECT execution_date FROM exchange.reserves_in WHERE reserve_in_serial_id=1;" | psql "$DB" -Aqt)
   1718     OLD_VAL=$(echo "SELECT (credit).val FROM exchange.reserves_in WHERE reserve_in_serial_id=1;" | psql "$DB" -Aqt)
   1719     RES_PUB=$(echo "SELECT reserve_pub FROM exchange.reserves_in WHERE reserve_in_serial_id=1;" | psql "$DB" -Aqt)
   1720     NEW_TIME=$(( OLD_TIME - 3024000000000 ))  # 5 weeks
   1721     NEW_CREDIT=$(( OLD_VAL + 100 ))
   1722     echo "UPDATE exchange.reserves_in SET execution_date='${NEW_TIME}',credit.val=${NEW_CREDIT} WHERE reserve_in_serial_id=1;" \
   1723         | psql -Aqt "$DB"
   1724     echo "UPDATE exchange.reserves SET current_balance.val=100+(current_balance).val WHERE reserve_pub='${RES_PUB}';" \
   1725         | psql -Aqt "$DB"
   1726 
   1727     # This time, run without the aggregator so the reserve closure is skipped!
   1728     run_audit
   1729     check_auditor_running
   1730 
   1731     echo -n "Testing reserve closure missing detected... "
   1732     check_report \
   1733         "reserve-not-closed-inconsistencies" \
   1734         "suppressed" "false"
   1735     echo -n "Testing balance updated correctly... "
   1736     check_not_balance \
   1737         "total_balance_reserve_not_closed" \
   1738         "TESTKUDOS:0" \
   1739         "Reported total amount wrong"
   1740 
   1741     # Undo
   1742     echo "UPDATE exchange.reserves_in SET execution_date='${OLD_TIME}',credit.val=${OLD_VAL} WHERE reserve_in_serial_id=1;" \
   1743         | psql -Aqt "$DB"
   1744     echo "UPDATE exchange.reserves SET current_balance.val=(current_balance).val-100 WHERE reserve_pub='${RES_PUB}';" \
   1745         | psql -Aqt "$DB"
   1746 
   1747     full_reload
   1748 }
   1749 
   1750 
   1751 # Test reserve closure reported but wire transfer missing detection
   1752 function test_21() {
   1753     echo "===========21: reserve closure missreported ================="
   1754 
   1755     OLD_TIME=$(echo "SELECT execution_date FROM exchange.reserves_in WHERE reserve_in_serial_id=1;" | psql "$DB" -Aqt)
   1756     OLD_VAL=$(echo "SELECT (credit).val FROM exchange.reserves_in WHERE reserve_in_serial_id=1;" | psql "$DB" -Aqt)
   1757     RES_PUB=$(echo "SELECT reserve_pub FROM exchange.reserves_in WHERE reserve_in_serial_id=1;" | psql "$DB" -Aqt)
   1758     OLD_EXP=$(echo "SELECT expiration_date FROM exchange.reserves WHERE reserve_pub='${RES_PUB}';" | psql "$DB" -Aqt)
   1759     VAL_DELTA=1
   1760     NEW_TIME=$(( OLD_TIME - 3024000000000 ))  # 5 weeks
   1761     NEW_EXP=$(( OLD_EXP - 3024000000000 ))  # 5 weeks
   1762     NEW_CREDIT=$(( OLD_VAL + VAL_DELTA ))
   1763     echo "UPDATE exchange.reserves_in SET execution_date='${NEW_TIME}',credit.val=${NEW_CREDIT} WHERE reserve_in_serial_id=1;" \
   1764         | psql -Aqt "$DB"
   1765     echo "UPDATE exchange.reserves SET current_balance.val=${VAL_DELTA}+(current_balance).val,expiration_date='${NEW_EXP}' WHERE reserve_pub='${RES_PUB}';" \
   1766         | psql -Aqt "$DB"
   1767 
   1768     # Need to first run the aggregator so the transfer is marked as done
   1769     pre_audit aggregator
   1770     stop_libeufin
   1771 
   1772     # remove wire transfer from bank DB
   1773     echo "DELETE FROM libeufin_bank.bank_account_transactions WHERE debtor_name='Exchange Company';" \
   1774         | psql "${DB}" -q
   1775 
   1776     launch_libeufin
   1777     audit_only
   1778     post_audit
   1779     check_auditor_running
   1780 
   1781     echo -n "Testing reserve_in inconsistency detection... "
   1782     check_report \
   1783         row-minor-inconsistencies \
   1784         "row_table" "reserves_in"
   1785 
   1786     echo -n "Testing lack of reserve closure transaction detected... "
   1787     check_report \
   1788         "closure-lags" \
   1789         "suppressed" "false"
   1790     echo -n "Checking closure lag amount ..."
   1791     check_report \
   1792         "closure-lags" \
   1793         "amount" "TESTKUDOS:${VAL_DELTA}"
   1794     echo -n "Checking closure lag total balance ..."
   1795     check_balance \
   1796         "total_closure_amount_lag" \
   1797         "TESTKUDOS:${VAL_DELTA}" \
   1798         "Reported total_closure_amount_lag wrong"
   1799     # cannot easily undo aggregator, hence full reload
   1800     full_reload
   1801 }
   1802 
   1803 
   1804 # Test use of withdraw-expired denomination key
   1805 function test_22() {
   1806     echo "===========22: denomination key expired ================="
   1807 
   1808     S_DENOM=$(echo 'SELECT denom_serials[1] FROM exchange.withdraw LIMIT 1;' | psql "$DB" -Aqt)
   1809 
   1810     OLD_START=$(echo "SELECT valid_from FROM exchange.denominations WHERE denominations_serial='${S_DENOM}';" | psql "$DB" -Aqt)
   1811     OLD_WEXP=$(echo "SELECT expire_withdraw FROM exchange.denominations WHERE denominations_serial='${S_DENOM}';" | psql "$DB" -Aqt)
   1812     # Basically expires 'immediately', so that the withdraw must have been 'invalid'
   1813     NEW_WEXP=$OLD_START
   1814 
   1815     echo "UPDATE exchange.denominations SET expire_withdraw=${NEW_WEXP} WHERE denominations_serial='${S_DENOM}';" | psql -Aqt "$DB"
   1816 
   1817 
   1818     run_audit
   1819     check_auditor_running
   1820 
   1821     echo -n "Testing inconsistency detection... "
   1822     check_report \
   1823         "denomination-key-validity-withdraw-inconsistencies" \
   1824         "suppressed" "false"
   1825     call_endpoint "denomination-key-validity-withdraw-inconsistencies"
   1826 
   1827     # Undo modification
   1828     echo "UPDATE exchange.denominations SET expire_withdraw=${OLD_WEXP} WHERE denominations_serial='${S_DENOM}';" | psql -Aqt "$DB"
   1829 
   1830     full_reload
   1831 }
   1832 
   1833 
   1834 # Test calculation of wire-out amounts
   1835 function test_23() {
   1836     echo "===========23: wire out calculations ================="
   1837 
   1838     # Need to first run the aggregator so the transfer is marked as done exists
   1839     pre_audit aggregator
   1840 
   1841     OLD_AMOUNT=$(echo "SELECT (amount).frac FROM exchange.wire_out WHERE wireout_uuid=1;" | psql "$DB" -Aqt)
   1842     NEW_AMOUNT=$(( OLD_AMOUNT - 1000000 ))
   1843     echo "UPDATE exchange.wire_out SET amount.frac=${NEW_AMOUNT} WHERE wireout_uuid=1;" \
   1844         | psql -Aqt "$DB"
   1845 
   1846     audit_only
   1847     post_audit
   1848     check_auditor_running
   1849 
   1850     echo -n "Testing inconsistency detection... "
   1851     check_report \
   1852         "wire-out-inconsistencies" \
   1853         "suppressed" "false"
   1854     echo -n "Testing inconsistency row report... "
   1855     check_report \
   1856         "wire-out-inconsistencies" \
   1857         "wire_out_row_id" "1"
   1858     echo -n "Testing inconsistency balance... "
   1859     check_balance \
   1860         "aggregation_total_wire_out_delta_plus" \
   1861         "TESTKUDOS:0" \
   1862         "Reported aggregation_total_wire_out_delta_plus wrong"
   1863     echo -n "Testing inconsistency balance change ... "
   1864     check_balance \
   1865         "aggregation_total_wire_out_delta_minus" \
   1866         "TESTKUDOS:0.01" \
   1867         "Reported aggregation_total_wire_out_delta_minus wrong"
   1868 
   1869     echo "Second pass: changing how amount is wrong to other direction"
   1870     NEW_AMOUNT=$(( OLD_AMOUNT + 1000000 ))
   1871     echo "UPDATE exchange.wire_out SET amount.frac=${NEW_AMOUNT} WHERE wireout_uuid=1;" | psql -Aqt "$DB"
   1872 
   1873     pre_audit
   1874     audit_only
   1875     post_audit
   1876 
   1877     echo -n "Testing inconsistency detection... "
   1878 
   1879     echo -n "Testing inconsistency detection... "
   1880     check_report \
   1881         "wire-out-inconsistencies" \
   1882         "suppressed" "false"
   1883     echo -n "Testing inconsistency row report... "
   1884     check_report \
   1885         "wire-out-inconsistencies" \
   1886         "wire_out_row_id" "1"
   1887     echo -n "Testing inconsistency balance... "
   1888     check_balance \
   1889         "aggregation_total_wire_out_delta_plus" \
   1890         "TESTKUDOS:0.01" \
   1891         "Reported aggregation_total_wire_out_delta_plus wrong"
   1892     echo -n "Testing inconsistency balance change ... "
   1893     check_balance \
   1894         "aggregation_total_wire_out_delta_minus" \
   1895         "TESTKUDOS:0" \
   1896         "Reported aggregation_total_wire_out_delta_minus wrong"
   1897 
   1898     # cannot easily undo aggregator, hence full reload
   1899     full_reload
   1900 }
   1901 
   1902 
   1903 # Test for missing deposits in exchange database.
   1904 function test_24() {
   1905     echo "===========24: deposits missing ==========="
   1906     # Modify denom_sig, so it is wrong
   1907     CNT=$(echo "SELECT COUNT(*) FROM auditor.auditor_deposit_confirmations;" | psql -Aqt "$DB")
   1908     if [ "$CNT" = "0" ]
   1909     then
   1910         echo "Skipping deposits missing test: no deposit confirmations in database!"
   1911     else
   1912         echo "DELETE FROM exchange.batch_deposits;" | psql -Aqt "$DB"
   1913         echo "DELETE FROM exchange.batch_deposits WHERE batch_deposit_serial_id=1;" \
   1914             | psql -Aqt "$DB"
   1915 
   1916         run_audit
   1917         check_auditor_running
   1918 
   1919         echo -n "Testing inconsistency detection... "
   1920         call_endpoint "balances"
   1921         check_report \
   1922             "deposit-confirmations" \
   1923             "suppressed" "false"
   1924         echo -n "Testing inconsistency detection balance change ... "
   1925         check_not_balance \
   1926             "total_missed_deposit_confirmations" \
   1927             "TESTKUDOS:0" \
   1928             "Expected non-zero total missing deposit confirmation amount"
   1929         # cannot easily undo DELETE, hence full reload
   1930         full_reload
   1931     fi
   1932 }
   1933 
   1934 
   1935 # Test for inconsistent coin history.
   1936 function test_25() {
   1937 
   1938     echo "=========25: inconsistent coin history========="
   1939 
   1940     # Drop refund, so coin history is bogus.
   1941     echo -n "Dropping refund from DB... "
   1942     echo "DELETE FROM exchange.refunds WHERE refund_serial_id=1;" \
   1943         | psql -At "$DB"
   1944 
   1945     run_audit aggregator
   1946     check_auditor_running
   1947 
   1948     echo -n "Testing inconsistency detection... "
   1949     check_report \
   1950         "coin-inconsistencies" \
   1951         "profitable" "true"
   1952     echo -n "Testing emergency risk reporting... "
   1953     check_report \
   1954         "emergencies" \
   1955         "denom_risk" "TESTKUDOS:10"
   1956     echo -n "Testing emergency loss reporting... "
   1957     # The dropped refund covered coin deposit #2, so the deposit's full
   1958     # amount is what the denomination is now short of.
   1959     check_report \
   1960         "emergencies" \
   1961         "denom_loss" "TESTKUDOS:7.02"
   1962     echo -n "Testing double-spending reporting... "
   1963     check_balance \
   1964         "coins_reported_emergency_risk_by_amount" \
   1965         "TESTKUDOS:10" \
   1966         "double-spending not detected"
   1967     echo -n "Testing balance loss update... "
   1968     check_balance \
   1969         "aggregation_total_coin_delta_minus" \
   1970         "TESTKUDOS:5.98" \
   1971         "aggregation total coin delta minus not reported"
   1972     # cannot easily undo DELETE, hence full reload
   1973     full_reload
   1974 }
   1975 
   1976 
   1977 # Test for deposit wire target malformed
   1978 function test_26() {
   1979     echo "===========26: deposit wire target malformed ================="
   1980 
   1981     # Expects 'payto_uri', not 'url' (also breaks signature, but we cannot even check that).
   1982     SERIAL=$(echo "SELECT batch_deposit_serial_id FROM exchange.coin_deposits WHERE (amount_with_fee).val=3 ORDER BY batch_deposit_serial_id LIMIT 1" | psql "$DB" -Aqt)
   1983     OLD_WIRE_ID=$(echo "SELECT wire_target_h_payto FROM exchange.batch_deposits WHERE batch_deposit_serial_id=${SERIAL};"  | psql "$DB" -Aqt)
   1984 # shellcheck disable=SC2028
   1985     echo "INSERT INTO exchange.wire_targets (payto_uri, wire_target_h_payto) VALUES ('payto://x-taler-bank/localhost/testuser-xxlargtp', '\x1e8f31936b3cee8f8afd3aac9e38b5db42d45b721ffc4eb1e5b9ddaf1565660b');" \
   1986         | psql "$DB" -Aqt
   1987 # shellcheck disable=SC2028
   1988     echo "UPDATE exchange.batch_deposits SET wire_target_h_payto='\x1e8f31936b3cee8f8afd3aac9e38b5db42d45b721ffc4eb1e5b9ddaf1565660b' WHERE batch_deposit_serial_id=${SERIAL};" \
   1989         | psql -Aqt "$DB"
   1990 
   1991     run_audit
   1992     check_auditor_running
   1993 
   1994     check_balance \
   1995         "coin_irregular_loss" \
   1996         "TESTKUDOS:3.02" \
   1997         "wrong total irregular coin loss"
   1998     call_endpoint "bad-sig-losses"
   1999     echo -n "Checking correct operation of loss reported... "
   2000     check_report \
   2001         "bad-sig-losses" \
   2002         "operation" "deposit"
   2003     echo -n "Checking correct loss reported... "
   2004     check_report \
   2005         "bad-sig-losses" \
   2006         "loss" "TESTKUDOS:3.02"
   2007     echo -n "Checking correct problem row ID reported... "
   2008     check_report \
   2009         "bad-sig-losses" \
   2010         "problem_row_id" "$SERIAL"
   2011 
   2012     # Undo:
   2013     echo "UPDATE exchange.batch_deposits SET wire_target_h_payto='$OLD_WIRE_ID' WHERE batch_deposit_serial_id=${SERIAL}" \
   2014         | psql -Aqt "$DB"
   2015 }
   2016 
   2017 
   2018 # Test where denom_sig in known_coins table is wrong
   2019 # (=> bad signature) AND the coin is used in aggregation
   2020 function test_27() {
   2021 
   2022     echo "===========27: known_coins signature wrong================="
   2023     # Modify denom_sig, so it is wrong
   2024     OLD_SIG=$(echo 'SELECT denom_sig FROM exchange.known_coins LIMIT 1;' | psql "$DB" -Aqt)
   2025     COIN_PUB=$(echo "SELECT coin_pub FROM exchange.known_coins WHERE denom_sig='$OLD_SIG';"  | psql "$DB" -Aqt)
   2026 # shellcheck disable=SC2028
   2027     echo "UPDATE exchange.known_coins SET denom_sig='\x0000000100000000287369672d76616c200a2028727361200a2020287320233542383731423743393036444643303442424430453039353246413642464132463537303139374131313437353746324632323332394644443146324643333445393939413336363430334233413133324444464239413833353833464536354442374335434445304441453035374438363336434541423834463843323843344446304144363030343430413038353435363039373833434431333239393736423642433437313041324632414132414435413833303432434346314139464635394244434346374436323238344143354544364131373739463430353032323241373838423837363535453434423145443831364244353638303232413123290a2020290a20290b' WHERE coin_pub='$COIN_PUB'" \
   2028         | psql -Aqt "$DB"
   2029 
   2030     run_audit aggregator
   2031     check_auditor_running
   2032 
   2033     echo -n "Testing inconsistency detection... "
   2034     check_report_neg \
   2035         "bad-sig-losses" \
   2036         "loss" "TESTKUDOS:0"
   2037     echo -n "Testing inconsistency detection operation attribution... "
   2038     check_report \
   2039         "bad-sig-losses" \
   2040         "operation" "wire"
   2041     echo -n "Testing table attribution for inconsistency... "
   2042     check_report \
   2043         "row-inconsistencies" \
   2044         "row_table" "deposit"
   2045     echo -n "Check signature loss was accumulated ..."
   2046     check_not_balance \
   2047         "aggregation_total_bad_sig_loss" \
   2048         "TESTKUDOS:0" \
   2049         "Wrong aggregation_total_bad_sig_loss"
   2050 
   2051     # cannot easily undo aggregator, hence full reload
   2052     full_reload
   2053 }
   2054 
   2055 
   2056 
   2057 # Test where fees known to the auditor differ from those
   2058 # accounted for by the exchange
   2059 function test_28() {
   2060     echo "===========28: withdraw fee inconsistency ================="
   2061 
   2062     echo "UPDATE exchange.withdraw SET amount_with_fee.val=(amount_with_fee).val+1 WHERE withdraw_id=1;" | psql -Aqt "$DB"
   2063 
   2064     run_audit
   2065     check_auditor_running
   2066 
   2067     echo -n "Testing inconsistency detection... "
   2068     check_report \
   2069         "row-inconsistencies" \
   2070         "row_table" "withdraw"
   2071     # Undo
   2072     full_reload
   2073 }
   2074 
   2075 
   2076 # Test where fees known to the auditor differ from those
   2077 # accounted for by the exchange
   2078 function test_29() {
   2079     echo "===========29: melt fee inconsistency ================="
   2080 
   2081     echo "UPDATE exchange.denominations SET fee_refresh.frac=5000000 WHERE (coin).val=10;" | psql -Aqt "$DB"
   2082 
   2083     run_audit
   2084     check_auditor_running
   2085 
   2086     echo -n "Testing inconsistency detection... "
   2087     check_report_neg \
   2088         "bad-sig-losses" \
   2089         "loss" "TESTKUDOS:0"
   2090     echo -n "Testing inconsistency was reported as profitable... "
   2091     check_report \
   2092         "amount-arithmetic-inconsistencies" \
   2093         "profitable" "true"
   2094     echo -n "Testing no emergency was raised... "
   2095     check_no_report "emergencies"
   2096 
   2097     # Undo
   2098     echo "UPDATE exchange.denominations SET fee_refresh.frac=3000000 WHERE (coin).val=10;" | psql -Aqt "$DB"
   2099 
   2100     full_reload
   2101 }
   2102 
   2103 
   2104 # Test where fees known to the auditor differ from those
   2105 # accounted for by the exchange
   2106 function test_30() {
   2107     echo "===========30: deposit fee inconsistency ================="
   2108 
   2109     echo "UPDATE exchange.denominations SET fee_deposit.frac=5000000 WHERE (coin).val=8;" | psql -Aqt "$DB"
   2110 
   2111     run_audit aggregator
   2112     check_auditor_running
   2113 
   2114     echo -n "Testing inconsistency detection... "
   2115 
   2116     check_not_balance \
   2117         "coin_irregular_loss" \
   2118         "TESTKUDOS:0" \
   2119         "Reported total coin_irregular_loss wrong"
   2120     check_report \
   2121         "bad-sig-losses" \
   2122         "operation" "deposit"
   2123     # Undo
   2124     echo "UPDATE exchange.denominations SET fee_deposit.frac=2000000 WHERE (coin).val=8;" | psql -Aqt "$DB"
   2125     full_reload
   2126 }
   2127 
   2128 
   2129 
   2130 
   2131 # Test where denom_sig in known_coins table is wrong
   2132 # (=> bad signature)
   2133 function test_31() {
   2134     echo "===========31: known_coins signature wrong w. aggregation================="
   2135     # Modify denom_sig, so it is wrong
   2136     OLD_SIG=$(echo 'SELECT denom_sig FROM exchange.known_coins LIMIT 1;' | psql "$DB" -Aqt)
   2137     COIN_PUB=$(echo "SELECT coin_pub FROM exchange.known_coins WHERE denom_sig='$OLD_SIG';"  | psql "$DB" -Aqt)
   2138 # shellcheck disable=SC2028
   2139     echo "UPDATE exchange.known_coins SET denom_sig='\x0000000100000000287369672d76616c200a2028727361200a2020287320233542383731423743393036444643303442424430453039353246413642464132463537303139374131313437353746324632323332394644443146324643333445393939413336363430334233413133324444464239413833353833464536354442374335434445304441453035374438363336434541423834463843323843344446304144363030343430413038353435363039373833434431333239393736423642433437313041324632414132414435413833303432434346314139464635394244434346374436323238344143354544364131373739463430353032323241373838423837363535453434423145443831364244353638303232413123290a2020290a20290b' WHERE coin_pub='$COIN_PUB'" \
   2140         | psql -Aqt "$DB"
   2141 
   2142     run_audit aggregator
   2143     check_auditor_running
   2144 
   2145     echo -n "Testing inconsistency detection... "
   2146     check_report \
   2147         "bad-sig-losses" \
   2148         "operation" "wire"
   2149     echo -n "Testing inconsistency balance update... "
   2150     check_not_balance \
   2151         "aggregation_total_bad_sig_loss" \
   2152         "TESTKUDOS:0" \
   2153         "Missed updating aggregation_total_bad_sig_loss"
   2154 
   2155     # Cannot undo aggregation, do full reload
   2156     full_reload
   2157     cleanup
   2158 }
   2159 
   2160 
   2161 # *************** Main test loop starts here **************
   2162 
   2163 
   2164 # Run all the tests against the database given in $1.
   2165 # Sets $fail to 0 on success, non-zero on failure.
   2166 function check_with_database()
   2167 {
   2168     BASEDB="$1"
   2169     CONF="$1.conf"
   2170     export CONF
   2171     echo "Running test suite with database $BASEDB using configuration $CONF"
   2172     MASTER_PRIV_FILE="${BASEDB}.mpriv"
   2173     taler-exchange-config \
   2174         -f \
   2175         -c "${CONF}" \
   2176         -s exchange-offline \
   2177         -o MASTER_PRIV_FILE \
   2178         -V "${MASTER_PRIV_FILE}"
   2179 
   2180     # Load database
   2181     full_reload
   2182 
   2183     # Run test suite
   2184     fail=0
   2185     for i in $TESTS
   2186     do
   2187         "test_$i"
   2188         if test 0 != $fail
   2189         then
   2190             break
   2191         fi
   2192     done
   2193     echo "Cleanup (disabled, leaving database $DB behind)"
   2194     # dropdb $DB
   2195 }
   2196 
   2197 # When the script is not run as root, setup a temporary directory for the
   2198 # postgres database.
   2199 # Sets PGHOST accordingly to the freshly created socket.
   2200 function perform_initdb() {
   2201     # Available directly in path?
   2202     INITDB_BIN=$(command -v initdb) || true
   2203     if [[ -n "$INITDB_BIN" ]]; then
   2204       echo " FOUND (in path) at $INITDB_BIN"
   2205     else
   2206         HAVE_INITDB=$(find /usr -name "initdb" 2> /dev/null \
   2207                           | head -1 2> /dev/null \
   2208                           | grep postgres) \
   2209             || exit_skip " MISSING"
   2210       echo " FOUND at $(dirname "$HAVE_INITDB")"
   2211       INITDB_BIN=$(echo "$HAVE_INITDB" | grep bin/initdb | grep postgres | sort -n | tail -n1)
   2212     fi
   2213     POSTGRES_PATH=$(dirname "$INITDB_BIN")
   2214 
   2215     TMPDIR="$MY_TMP_DIR/postgres"
   2216     mkdir -p "$TMPDIR"
   2217     echo -n "Setting up Postgres DB at $TMPDIR ..."
   2218     $INITDB_BIN \
   2219         --no-sync \
   2220         --auth=trust \
   2221         -D "${TMPDIR}" \
   2222         > "${MY_TMP_DIR}/postgres-dbinit.log" \
   2223         2> "${MY_TMP_DIR}/postgres-dbinit.err" \
   2224         || {
   2225         echo "FAILED!"
   2226         echo "Last entries in ${MY_TMP_DIR}/postgres-dbinit.err:"
   2227         tail "${MY_TMP_DIR}/postgres-dbinit.err"
   2228         exit 1
   2229     }
   2230     echo "DONE"
   2231 
   2232     # Once we move to PG16, we can use:
   2233     #    --set listen_addresses='' \
   2234     #    --set fsync=off \
   2235     #    --set max_wal_senders=0 \
   2236     #    --set synchronous_commit=off \
   2237     #    --set wal_level=minimal \
   2238     #    --set unix_socket_directories="${TMPDIR}/sockets" \
   2239 
   2240 
   2241     SOCKETDIR="${TMPDIR}/sockets"
   2242     mkdir "${SOCKETDIR}"
   2243 
   2244     echo -n "Launching Postgres service"
   2245 
   2246     cat - >> "$TMPDIR/postgresql.conf" <<EOF
   2247 unix_socket_directories='${TMPDIR}/sockets'
   2248 fsync=off
   2249 max_wal_senders=0
   2250 synchronous_commit=off
   2251 wal_level=minimal
   2252 listen_addresses=''
   2253 EOF
   2254 
   2255     grep -v host \
   2256          < "$TMPDIR/pg_hba.conf" \
   2257          > "$TMPDIR/pg_hba.conf.new"
   2258     mv "$TMPDIR/pg_hba.conf.new" "$TMPDIR/pg_hba.conf"
   2259     "${POSTGRES_PATH}/pg_ctl" \
   2260         -D "$TMPDIR" \
   2261         -l "${MY_TMP_DIR}/postgres.log" \
   2262         start \
   2263         > "${MY_TMP_DIR}/postgres-start.log" \
   2264         2> "${MY_TMP_DIR}/postgres-start.err"
   2265     echo " DONE"
   2266     PGHOST="$TMPDIR/sockets"
   2267     export PGHOST
   2268 }
   2269 
   2270 
   2271 # *************** Main logic starts here **************
   2272 
   2273 # ####### Setup globals ######
   2274 # Postgres database to use (must match configuration file)
   2275 export DB="auditor-basedb"
   2276 
   2277 # test required commands exist
   2278 echo "Testing for jq"
   2279 jq -h > /dev/null || exit_skip "jq required"
   2280 echo "Testing for taler-merchant-config"
   2281 taler-merchant-config -h > /dev/null || exit_skip "taler-merchant-config required"
   2282 echo "Testing for taler-merchant-httpd"
   2283 taler-merchant-httpd -h > /dev/null || exit_skip "taler-merchant-httpd required"
   2284 echo "Testing for faketime"
   2285 faketime -h > /dev/null || exit_skip "faketime required"
   2286 # NOTE: really check for all three libeufin commands?
   2287 echo "Testing for libeufin"
   2288 libeufin-bank --help >/dev/null 2> /dev/null </dev/null || exit_skip "libeufin required"
   2289 echo "Testing for taler-wallet-cli"
   2290 taler-wallet-cli -h >/dev/null </dev/null 2>/dev/null || exit_skip "taler-wallet-cli required"
   2291 
   2292 
   2293 echo -n "Testing for Postgres"
   2294 
   2295 MY_TMP_DIR=$(mktemp -d /tmp/taler-auditor-basedbXXXXXX)
   2296 echo "Using $MY_TMP_DIR for logging and temporary data"
   2297 
   2298 # If run as root, simply use the running postgres instance.
   2299 # Otherwise create a temporary storage space for postgres.
   2300 [ $(id -u) == 0 ] || perform_initdb
   2301 
   2302 MYDIR="${MY_TMP_DIR}/basedb"
   2303 mkdir -p "${MYDIR}"
   2304 
   2305 if [ -z ${REUSE_BASEDB_DIR+x} ]
   2306 then
   2307     echo "Generating fresh database at $MYDIR"
   2308 
   2309     if faketime -f '-1 d' ./generate-auditor-basedb.sh -d "$MYDIR/$DB"
   2310     then
   2311         echo -n "Reset 'auditor-basedb' database at ${PGHOST:-} ..."
   2312         dropdb --if-exists "auditor-basedb" > /dev/null 2> /dev/null || true
   2313         createdb "auditor-basedb" || exit_skip "Could not create database '$BASEDB' at ${PGHOST:-}"
   2314         echo " DONE"
   2315     else
   2316         echo "Generation failed"
   2317         exit 1
   2318     fi
   2319     echo "To reuse this database in the future, use:"
   2320     echo "export REUSE_BASEDB_DIR=$MY_TMP_DIR"
   2321 else
   2322     echo "Reusing existing database from ${REUSE_BASEDB_DIR}"
   2323     cp -r "${REUSE_BASEDB_DIR}/basedb"/* "${MYDIR}/"
   2324 fi
   2325 
   2326 check_with_database "$MYDIR/$DB"
   2327 if [ "$fail" != "0" ]
   2328 then
   2329     exit "$fail"
   2330 fi
   2331 
   2332 if [ -z "${REUSE_BASEDB_DIR+x}" ]
   2333 then
   2334     echo "Run 'export REUSE_BASEDB_DIR=${MY_TMP_DIR}' to re-run tests against the same database"
   2335 fi
   2336 
   2337 exit 0