exchange

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

generate-revoke-basedb.sh (12738B)


      1 #!/bin/bash
      2 # Script to test revocation.
      3 #
      4 # Requires the wallet CLI to be installed and in the path.  Furthermore, the
      5 # user running this script must be Postgres superuser and be allowed to
      6 # create/drop databases.
      7 #
      8 set -eu
      9 # set -x
     10 
     11 # The revocation test depends on the wallet picking specific coins (it
     12 # revokes the denomination of a particular coin), so coin selection has to
     13 # be deterministic.  See generate-auditor-basedb.sh and
     14 # https://bugs.gnunet.org/view.php?id=11272.
     15 export TALER_WALLET_COINSEL="legacy-2024"
     16 
     17 . setup.sh
     18 
     19 echo -n "Testing for curl ..."
     20 curl --help >/dev/null </dev/null || exit_skip " MISSING"
     21 echo " FOUND"
     22 
     23 echo "Testing for taler-merchant-config"
     24 taler-merchant-config -h > /dev/null || exit_skip "taler-merchant-config required"
     25 echo "Testing for taler-merchant-httpd"
     26 taler-merchant-httpd -h > /dev/null || exit_skip "taler-merchant-httpd required"
     27 
     28 # reset database
     29 echo -n "Reset 'auditor-basedb' database ..."
     30 dropdb "auditor-basedb" >/dev/null 2>/dev/null || true
     31 createdb "auditor-basedb" || exit_skip "Could not create database '$BASEDB'"
     32 echo " DONE"
     33 
     34 # Launch exchange, merchant and bank.
     35 setup -c generate-auditor-basedb.conf \
     36       -abemw \
     37       -d "iban"
     38 CONF="generate-auditor-basedb.conf.edited"
     39 
     40 # obtain key configuration data
     41 EXCHANGE_URL=$(taler-exchange-config -c "$CONF" -s EXCHANGE -o BASE_URL)
     42 MERCHANT_PORT=$(taler-merchant-config -c "$CONF" -s MERCHANT -o PORT)
     43 MERCHANT_URL="http://localhost:${MERCHANT_PORT}/"
     44 BANK_PORT=$(taler-exchange-config -c "$CONF" -s BANK -o HTTP_PORT)
     45 BANK_URL="http://localhost:${BANK_PORT}/"
     46 
     47 
     48 # Setup merchant
     49 export MERCHANT_URL
     50 echo -n "Setting up merchant ..."
     51 curl -H "Content-Type: application/json" -X POST -d '{"auth": {"method": "external"},"id":"admin","name":"admin","address":{},"jurisdiction":{},"default_max_wire_fee":"TESTKUDOS:1", "default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000},"use_stefan":true}' "${MERCHANT_URL}management/instances"
     52 echo " DONE"
     53 
     54 echo -n "Setting up merchant account ..."
     55 FORTYTHREE="payto://iban/DE12500105170648489890?receiver-name=Merchant43"
     56 STATUS=$(curl -H "Content-Type: application/json" -X POST \
     57     "${MERCHANT_URL}private/accounts" \
     58     -d '{"payto_uri":"'"$FORTYTHREE"'"}' \
     59     -w "%{http_code}" -s -o /dev/null)
     60 if [ "$STATUS" != "200" ]
     61 then
     62     exit_fail "Expected 200 OK. Got: $STATUS"
     63 fi
     64 echo " DONE"
     65 
     66 echo -n "Setting up libeufin merchant account ..."
     67 libeufin-bank create-account \
     68               --config="${CONF}" \
     69               --name="Merchant43" \
     70               --username="Merchant43" \
     71               --password="password" \
     72               --payto_uri="payto://iban/DE12500105170648489890?receiver-name=Merchant43"
     73 echo " DONE"
     74 
     75 
     76 # run wallet CLI
     77 echo "Running wallet"
     78 
     79 export WALLET_DB="wallet.wdb"
     80 rm -f "$WALLET_DB"
     81 
     82 wlog="taler-wallet-cli-withdraw.log"
     83 taler-wallet-cli \
     84     --no-throttle \
     85     --wallet-db="$WALLET_DB" \
     86     api \
     87     --expect-success 'withdrawTestBalance' \
     88   "$(jq -n '
     89     {
     90       amount: "TESTKUDOS:8",
     91       corebankApiBaseUrl: $BANK_URL,
     92       exchangeBaseUrl: $EXCHANGE_URL,
     93     }' \
     94     --arg BANK_URL "$BANK_URL" \
     95     --arg EXCHANGE_URL "$EXCHANGE_URL"
     96   )" &> $wlog || {
     97     echo " FAILED(withdraw)!  Last entries in $wlog:"
     98     tail $wlog
     99     exit 2
    100 }
    101 
    102 taler-wallet-cli \
    103     --no-throttle \
    104     --wallet-db="$WALLET_DB" \
    105     run-until-done \
    106     &> taler-wallet-cli-withdraw-finish.log
    107 
    108 export COINS=$(taler-wallet-cli --wallet-db="$WALLET_DB" advanced dump-coins)
    109 
    110 echo -n "COINS are:"
    111 echo "$COINS"
    112 
    113 export COINS
    114 # Find coin we want to revoke
    115 export rc=$(echo "$COINS" | jq -r '[.coins[] | select((.denomValue == "TESTKUDOS:2"))][0] | .coinPub')
    116 # Find the denom
    117 export rd=$(echo "$COINS" | jq -r '[.coins[] | select((.denomValue == "TESTKUDOS:2"))][0] | .denomPubHash')
    118 
    119 # This database is all about recoup, which the exchange currently does not
    120 # implement: the recoup handlers are compiled out behind FIXME_9828 (see
    121 # src/exchange/taler-exchange-httpd.c and
    122 # https://bugs.gnunet.org/view.php?id=9828).  Without them the wallet can
    123 # never recoup the coins of the revoked denomination and we would spin until
    124 # the test times out, so detect that up front and skip.
    125 echo -n "Checking that the exchange implements recoup ..."
    126 RECOUP_CODE=$(curl -s -X POST \
    127                    -o "${MY_TMP_DIR}/recoup-probe.json" \
    128                    -w "%{http_code}" \
    129                    -H "Content-Type: application/json" \
    130                    -d '{}' \
    131                    "${EXCHANGE_URL}coins/${rc}/recoup")
    132 if [ "$RECOUP_CODE" = "404" ] &&
    133    [ "$(jq -r '.code' < "${MY_TMP_DIR}/recoup-probe.json")" = "1001" ]
    134 then
    135     echo " NO"
    136     exit_skip "exchange has no /coins/\$COIN_PUB/recoup endpoint (recoup is disabled, see FIXME_9828)"
    137 fi
    138 echo " YES"
    139 
    140 echo -n "Revoking denomination ${rd} (to affect coin ${rc}) ..."
    141 # Find all other coins, which will be suspended
    142 export susp=$(echo "$COINS" | jq --arg rc "$rc" '[.coins[] | select(.coinPub != $rc) | .coinPub]')
    143 
    144 # Do the revocation
    145 taler-exchange-offline \
    146     -c "$CONF" \
    147     revoke-denomination "${rd}" \
    148     upload \
    149     &> taler-exchange-offline-revoke.log
    150 echo "DONE"
    151 
    152 echo -n "Signing replacement keys ..."
    153 sleep 1 # Give exchange time to create replacmenent key
    154 
    155 # Re-sign replacement keys
    156 taler-auditor-offline \
    157     -c "$CONF" \
    158     download \
    159     sign \
    160     upload \
    161     &> taler-auditor-offline-reinit.log
    162 echo " DONE"
    163 
    164 # Now we suspend the other coins, so later we will pay with the recouped coin
    165 taler-wallet-cli \
    166     --wallet-db="$WALLET_DB" \
    167     advanced \
    168     suspend-coins "$susp"
    169 
    170 # Update exchange /keys so recoup gets scheduled
    171 taler-wallet-cli \
    172     --wallet-db="$WALLET_DB" \
    173     exchanges \
    174     update \
    175     -f "$EXCHANGE_URL"
    176 
    177 # Block until scheduled operations are done
    178 taler-wallet-cli \
    179     --wallet-db="$WALLET_DB"\
    180     run-until-done
    181 
    182 # Now we buy something, only the coins resulting from recoup will be
    183 # used, as other ones are suspended
    184 taler-wallet-cli \
    185     --no-throttle \
    186     --wallet-db="$WALLET_DB" \
    187     api \
    188     'testPay' \
    189   "$(jq -n '
    190     {
    191       amount: "TESTKUDOS:1",
    192       merchantBaseUrl: $MERCHANT_URL,
    193       summary: "foo",
    194     }' \
    195     --arg MERCHANT_URL "$MERCHANT_URL"
    196   )"
    197 
    198 taler-wallet-cli \
    199     --wallet-db="$WALLET_DB" \
    200     run-until-done
    201 
    202 echo "Purchase with recoup'ed coin (via reserve) done"
    203 
    204 # Re-read the coins: the recoup and the purchase above changed the wallet's
    205 # coin set, so the dump taken before the first revocation is stale.
    206 COINS=$(taler-wallet-cli --wallet-db="$WALLET_DB" advanced dump-coins)
    207 export COINS
    208 
    209 # Find coin we want to refresh, then revoke
    210 export rrc=$(echo "$COINS" | jq -r '[.coins[] | select((.denomValue == "TESTKUDOS:5"))][0] | .coinPub')
    211 # Find the denom
    212 export zombie_denom=$(echo "$COINS" | jq -r '[.coins[] | select((.denomValue == "TESTKUDOS:5"))][0] | .denomPubHash')
    213 
    214 echo "Will refresh coin ${rrc} of denomination ${zombie_denom}"
    215 # Find all other coins, which will be suspended
    216 export susp=$(echo "$COINS" | jq --arg rrc "$rrc" '[.coins[] | select(.coinPub != $rrc) | .coinPub]')
    217 
    218 # Travel into the future! (must match DURATION_WITHDRAW option)
    219 export TIMETRAVEL="--timetravel=604800000000"
    220 
    221 echo "Launching exchange 1 week in the future"
    222 # The exchange and its security modules were started by
    223 # taler-unified-setup.sh, so we do not have their PIDs; stop them by name
    224 # and bring them back up with the time offset applied.
    225 for proc in taler-exchange-httpd \
    226             taler-exchange-secmod-rsa \
    227             taler-exchange-secmod-cs \
    228             taler-exchange-secmod-eddsa
    229 do
    230     pkill -x -u "$(id -u)" -TERM "$proc" || true
    231 done
    232 # Give them a moment to release their sockets
    233 sleep 1
    234 taler-exchange-secmod-eddsa $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-secmod-eddsa.log" &
    235 SIGNKEY_HELPER_PID=$!
    236 taler-exchange-secmod-rsa $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-secmod-rsa.log" &
    237 RSA_DENOM_HELPER_PID=$!
    238 taler-exchange-secmod-cs $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-secmod-cs.log" &
    239 CS_DENOM_HELPER_PID=$!
    240 export SIGNKEY_HELPER_PID RSA_DENOM_HELPER_PID CS_DENOM_HELPER_PID
    241 taler-exchange-httpd $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-httpd.log" &
    242 export EXCHANGE_PID=$!
    243 
    244 # Wait for exchange to be available
    245 OK=0
    246 for n in `seq 1 100`
    247 do
    248     echo -n "."
    249     sleep 0.2
    250     # exchange
    251     wget "${EXCHANGE_URL}config" -o /dev/null -O /dev/null >/dev/null || continue
    252     OK=1
    253     break
    254 done
    255 if [ 1 != "$OK" ]
    256 then
    257     exit_fail "Failed to restart exchange in the future"
    258 fi
    259 echo " DONE"
    260 
    261 echo "Refreshing coin $rrc"
    262 taler-wallet-cli \
    263     "$TIMETRAVEL" \
    264     --wallet-db="$WALLET_DB" \
    265     advanced force-refresh \
    266     "$rrc"
    267 taler-wallet-cli \
    268     "$TIMETRAVEL" \
    269     --wallet-db="$WALLET_DB" \
    270     run-until-done
    271 
    272 # Update our list of the coins
    273 export coins=$(taler-wallet-cli "$TIMETRAVEL" --wallet-db="$WALLET_DB" advanced dump-coins)
    274 
    275 # Find resulting refreshed coin
    276 export freshc=$(echo "$coins" | jq -r --arg rrc "$rrc" \
    277   '[.coins[] | select((.refreshParentCoinPub == $rrc) and .denomValue == "TESTKUDOS:0.1")][0] | .coinPub'
    278 )
    279 
    280 # Find the denom of freshc
    281 export fresh_denom=$(echo "$coins" | jq -r --arg rrc "$rrc" \
    282   '[.coins[] | select((.refreshParentCoinPub == $rrc) and .denomValue == "TESTKUDOS:0.1")][0] | .denomPubHash'
    283 )
    284 
    285 echo "Coin ${freshc} of denomination ${fresh_denom} is the result of the refresh"
    286 
    287 # Find all other coins, which will be suspended
    288 export susp=$(echo "$coins" | jq --arg freshc "$freshc" '[.coins[] | select(.coinPub != $freshc) | .coinPub]')
    289 
    290 
    291 # Do the revocation of freshc
    292 echo "Revoking ${fresh_denom} (to affect coin ${freshc})"
    293 taler-exchange-offline \
    294     -c "$CONF" \
    295     revoke-denomination \
    296     "${fresh_denom}" \
    297     upload &> taler-exchange-offline-revoke-2.log
    298 
    299 sleep 1 # Give exchange time to create replacmenent key
    300 
    301 # Re-sign replacement keys
    302 taler-auditor-offline \
    303     -c "$CONF" \
    304     download \
    305     sign \
    306     upload &> taler-auditor-offline.log
    307 
    308 # Now we suspend the other coins, so later we will pay with the recouped coin
    309 taler-wallet-cli \
    310     "$TIMETRAVEL" \
    311     --wallet-db="$WALLET_DB" \
    312     advanced \
    313     suspend-coins "$susp"
    314 
    315 # Update exchange /keys so recoup gets scheduled
    316 taler-wallet-cli \
    317     "$TIMETRAVEL"\
    318     --wallet-db="$WALLET_DB" \
    319     exchanges update \
    320     -f "$EXCHANGE_URL"
    321 
    322 # Block until scheduled operations are done
    323 taler-wallet-cli \
    324     "$TIMETRAVEL" \
    325     --wallet-db="$WALLET_DB" \
    326     run-until-done
    327 
    328 echo "Restarting merchant (so new keys are known)"
    329 pkill -x -u "$(id -u)" -TERM taler-merchant-httpd || true
    330 sleep 1
    331 taler-merchant-httpd \
    332     -c "$CONF" \
    333     -L INFO \
    334     2> ${MY_TMP_DIR}/taler-merchant-httpd.log &
    335 MERCHANT_PID=$!
    336 export MERCHANT_PID
    337 
    338 # Wait for merchant to be again available
    339 OK=0
    340 for n in `seq 1 100`
    341 do
    342     echo -n "."
    343     sleep 0.2
    344     # merchant
    345     wget "${MERCHANT_URL}config" -o /dev/null -O /dev/null >/dev/null || continue
    346     OK=1
    347     break
    348 done
    349 if [ 1 != "$OK" ]
    350 then
    351     exit_fail "Failed to restart merchant"
    352 fi
    353 echo " DONE"
    354 
    355 # Now we buy something, only the coins resulting from recoup+refresh will be
    356 # used, as other ones are suspended
    357 taler-wallet-cli $TIMETRAVEL --no-throttle --wallet-db=$WALLET_DB api 'testPay' \
    358   "$(jq -n '
    359     {
    360       amount: "TESTKUDOS:0.02",
    361       merchantBaseUrl: $MERCHANT_URL,
    362       summary: "bar",
    363     }' \
    364     --arg MERCHANT_URL $MERCHANT_URL
    365   )"
    366 taler-wallet-cli \
    367     "$TIMETRAVEL" \
    368     --wallet-db="$WALLET_DB" \
    369     run-until-done
    370 
    371 echo "Bought something with refresh-recouped coin"
    372 
    373 echo "Shutting down services"
    374 # Stop the exchange/merchant processes we restarted ourselves first: they
    375 # are not children of taler-unified-setup.sh, so its teardown misses them
    376 # and a bare 'wait' below would block forever.
    377 for pid in "${EXCHANGE_PID:-}" \
    378            "${MERCHANT_PID:-}" \
    379            "${RSA_DENOM_HELPER_PID:-}" \
    380            "${CS_DENOM_HELPER_PID:-}" \
    381            "${SIGNKEY_HELPER_PID:-}"
    382 do
    383     if [ -n "$pid" ]
    384     then
    385         kill -TERM "$pid" 2> /dev/null || true
    386         wait "$pid" 2> /dev/null || true
    387     fi
    388 done
    389 exit_cleanup
    390 unset SETUP_PID
    391 
    392 
    393 # Where do we write the result?
    394 export BASEDB=${1:-"revoke-basedb"}
    395 
    396 
    397 # Dump database
    398 mkdir -p "$(dirname "$BASEDB")"
    399 echo "Dumping database ${BASEDB}.sql"
    400 pg_dump -O "auditor-basedb" | sed -e '/AS integer/d' > "${BASEDB}.sql"
    401 cp "${CONF}" "${BASEDB}.conf"
    402 cp "$(taler-exchange-config -c "${CONF}" -s exchange-offline -o MASTER_PRIV_FILE -f)" "${BASEDB}.mpriv"
    403 
    404 # clean up
    405 echo -n "Final clean up ..."
    406 dropdb "auditor-basedb"
    407 echo " DONE"
    408 
    409 echo "====================================="
    410 echo "Finished generation of ${BASEDB}.sql"
    411 echo "====================================="
    412 
    413 exit 0