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 (12288B)


      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.  The exchange implements the batch
    120 # recoup protocol (POST /recoup-withdraw and /recoup-refresh, vRECOUP, see
    121 # https://bugs.gnunet.org/view.php?id=9828), but taler-wallet-cli does not
    122 # yet: after the revocation below the wallet would never recoup the coins of
    123 # the revoked denomination and we would spin until the test times out.
    124 # Remove this skip once wallet-core supports vRECOUP.
    125 exit_skip "taler-wallet-cli does not implement the batch recoup protocol (vRECOUP, #9828) yet"
    126 
    127 echo -n "Revoking denomination ${rd} (to affect coin ${rc}) ..."
    128 # Find all other coins, which will be suspended
    129 export susp=$(echo "$COINS" | jq --arg rc "$rc" '[.coins[] | select(.coinPub != $rc) | .coinPub]')
    130 
    131 # Do the revocation
    132 taler-exchange-offline \
    133     -c "$CONF" \
    134     revoke-denomination "${rd}" \
    135     upload \
    136     &> taler-exchange-offline-revoke.log
    137 echo "DONE"
    138 
    139 echo -n "Signing replacement keys ..."
    140 sleep 1 # Give exchange time to create replacmenent key
    141 
    142 # Re-sign replacement keys
    143 taler-auditor-offline \
    144     -c "$CONF" \
    145     download \
    146     sign \
    147     upload \
    148     &> taler-auditor-offline-reinit.log
    149 echo " DONE"
    150 
    151 # Now we suspend the other coins, so later we will pay with the recouped coin
    152 taler-wallet-cli \
    153     --wallet-db="$WALLET_DB" \
    154     advanced \
    155     suspend-coins "$susp"
    156 
    157 # Update exchange /keys so recoup gets scheduled
    158 taler-wallet-cli \
    159     --wallet-db="$WALLET_DB" \
    160     exchanges \
    161     update \
    162     -f "$EXCHANGE_URL"
    163 
    164 # Block until scheduled operations are done
    165 taler-wallet-cli \
    166     --wallet-db="$WALLET_DB"\
    167     run-until-done
    168 
    169 # Now we buy something, only the coins resulting from recoup will be
    170 # used, as other ones are suspended
    171 taler-wallet-cli \
    172     --no-throttle \
    173     --wallet-db="$WALLET_DB" \
    174     api \
    175     'testPay' \
    176   "$(jq -n '
    177     {
    178       amount: "TESTKUDOS:1",
    179       merchantBaseUrl: $MERCHANT_URL,
    180       summary: "foo",
    181     }' \
    182     --arg MERCHANT_URL "$MERCHANT_URL"
    183   )"
    184 
    185 taler-wallet-cli \
    186     --wallet-db="$WALLET_DB" \
    187     run-until-done
    188 
    189 echo "Purchase with recoup'ed coin (via reserve) done"
    190 
    191 # Re-read the coins: the recoup and the purchase above changed the wallet's
    192 # coin set, so the dump taken before the first revocation is stale.
    193 COINS=$(taler-wallet-cli --wallet-db="$WALLET_DB" advanced dump-coins)
    194 export COINS
    195 
    196 # Find coin we want to refresh, then revoke
    197 export rrc=$(echo "$COINS" | jq -r '[.coins[] | select((.denomValue == "TESTKUDOS:5"))][0] | .coinPub')
    198 # Find the denom
    199 export zombie_denom=$(echo "$COINS" | jq -r '[.coins[] | select((.denomValue == "TESTKUDOS:5"))][0] | .denomPubHash')
    200 
    201 echo "Will refresh coin ${rrc} of denomination ${zombie_denom}"
    202 # Find all other coins, which will be suspended
    203 export susp=$(echo "$COINS" | jq --arg rrc "$rrc" '[.coins[] | select(.coinPub != $rrc) | .coinPub]')
    204 
    205 # Travel into the future! (must match DURATION_WITHDRAW option)
    206 export TIMETRAVEL="--timetravel=604800000000"
    207 
    208 echo "Launching exchange 1 week in the future"
    209 # The exchange and its security modules were started by
    210 # taler-unified-setup.sh, so we do not have their PIDs; stop them by name
    211 # and bring them back up with the time offset applied.
    212 for proc in taler-exchange-httpd \
    213             taler-exchange-secmod-rsa \
    214             taler-exchange-secmod-cs \
    215             taler-exchange-secmod-eddsa
    216 do
    217     pkill -x -u "$(id -u)" -TERM "$proc" || true
    218 done
    219 # Give them a moment to release their sockets
    220 sleep 1
    221 taler-exchange-secmod-eddsa $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-secmod-eddsa.log" &
    222 SIGNKEY_HELPER_PID=$!
    223 taler-exchange-secmod-rsa $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-secmod-rsa.log" &
    224 RSA_DENOM_HELPER_PID=$!
    225 taler-exchange-secmod-cs $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-secmod-cs.log" &
    226 CS_DENOM_HELPER_PID=$!
    227 export SIGNKEY_HELPER_PID RSA_DENOM_HELPER_PID CS_DENOM_HELPER_PID
    228 taler-exchange-httpd $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-httpd.log" &
    229 export EXCHANGE_PID=$!
    230 
    231 # Wait for exchange to be available
    232 OK=0
    233 for n in `seq 1 100`
    234 do
    235     echo -n "."
    236     sleep 0.2
    237     # exchange
    238     wget "${EXCHANGE_URL}config" -o /dev/null -O /dev/null >/dev/null || continue
    239     OK=1
    240     break
    241 done
    242 if [ 1 != "$OK" ]
    243 then
    244     exit_fail "Failed to restart exchange in the future"
    245 fi
    246 echo " DONE"
    247 
    248 echo "Refreshing coin $rrc"
    249 taler-wallet-cli \
    250     "$TIMETRAVEL" \
    251     --wallet-db="$WALLET_DB" \
    252     advanced force-refresh \
    253     "$rrc"
    254 taler-wallet-cli \
    255     "$TIMETRAVEL" \
    256     --wallet-db="$WALLET_DB" \
    257     run-until-done
    258 
    259 # Update our list of the coins
    260 export coins=$(taler-wallet-cli "$TIMETRAVEL" --wallet-db="$WALLET_DB" advanced dump-coins)
    261 
    262 # Find resulting refreshed coin
    263 export freshc=$(echo "$coins" | jq -r --arg rrc "$rrc" \
    264   '[.coins[] | select((.refreshParentCoinPub == $rrc) and .denomValue == "TESTKUDOS:0.1")][0] | .coinPub'
    265 )
    266 
    267 # Find the denom of freshc
    268 export fresh_denom=$(echo "$coins" | jq -r --arg rrc "$rrc" \
    269   '[.coins[] | select((.refreshParentCoinPub == $rrc) and .denomValue == "TESTKUDOS:0.1")][0] | .denomPubHash'
    270 )
    271 
    272 echo "Coin ${freshc} of denomination ${fresh_denom} is the result of the refresh"
    273 
    274 # Find all other coins, which will be suspended
    275 export susp=$(echo "$coins" | jq --arg freshc "$freshc" '[.coins[] | select(.coinPub != $freshc) | .coinPub]')
    276 
    277 
    278 # Do the revocation of freshc
    279 echo "Revoking ${fresh_denom} (to affect coin ${freshc})"
    280 taler-exchange-offline \
    281     -c "$CONF" \
    282     revoke-denomination \
    283     "${fresh_denom}" \
    284     upload &> taler-exchange-offline-revoke-2.log
    285 
    286 sleep 1 # Give exchange time to create replacmenent key
    287 
    288 # Re-sign replacement keys
    289 taler-auditor-offline \
    290     -c "$CONF" \
    291     download \
    292     sign \
    293     upload &> taler-auditor-offline.log
    294 
    295 # Now we suspend the other coins, so later we will pay with the recouped coin
    296 taler-wallet-cli \
    297     "$TIMETRAVEL" \
    298     --wallet-db="$WALLET_DB" \
    299     advanced \
    300     suspend-coins "$susp"
    301 
    302 # Update exchange /keys so recoup gets scheduled
    303 taler-wallet-cli \
    304     "$TIMETRAVEL"\
    305     --wallet-db="$WALLET_DB" \
    306     exchanges update \
    307     -f "$EXCHANGE_URL"
    308 
    309 # Block until scheduled operations are done
    310 taler-wallet-cli \
    311     "$TIMETRAVEL" \
    312     --wallet-db="$WALLET_DB" \
    313     run-until-done
    314 
    315 echo "Restarting merchant (so new keys are known)"
    316 pkill -x -u "$(id -u)" -TERM taler-merchant-httpd || true
    317 sleep 1
    318 taler-merchant-httpd \
    319     -c "$CONF" \
    320     -L INFO \
    321     2> ${MY_TMP_DIR}/taler-merchant-httpd.log &
    322 MERCHANT_PID=$!
    323 export MERCHANT_PID
    324 
    325 # Wait for merchant to be again available
    326 OK=0
    327 for n in `seq 1 100`
    328 do
    329     echo -n "."
    330     sleep 0.2
    331     # merchant
    332     wget "${MERCHANT_URL}config" -o /dev/null -O /dev/null >/dev/null || continue
    333     OK=1
    334     break
    335 done
    336 if [ 1 != "$OK" ]
    337 then
    338     exit_fail "Failed to restart merchant"
    339 fi
    340 echo " DONE"
    341 
    342 # Now we buy something, only the coins resulting from recoup+refresh will be
    343 # used, as other ones are suspended
    344 taler-wallet-cli $TIMETRAVEL --no-throttle --wallet-db=$WALLET_DB api 'testPay' \
    345   "$(jq -n '
    346     {
    347       amount: "TESTKUDOS:0.02",
    348       merchantBaseUrl: $MERCHANT_URL,
    349       summary: "bar",
    350     }' \
    351     --arg MERCHANT_URL $MERCHANT_URL
    352   )"
    353 taler-wallet-cli \
    354     "$TIMETRAVEL" \
    355     --wallet-db="$WALLET_DB" \
    356     run-until-done
    357 
    358 echo "Bought something with refresh-recouped coin"
    359 
    360 echo "Shutting down services"
    361 # Stop the exchange/merchant processes we restarted ourselves first: they
    362 # are not children of taler-unified-setup.sh, so its teardown misses them
    363 # and a bare 'wait' below would block forever.
    364 for pid in "${EXCHANGE_PID:-}" \
    365            "${MERCHANT_PID:-}" \
    366            "${RSA_DENOM_HELPER_PID:-}" \
    367            "${CS_DENOM_HELPER_PID:-}" \
    368            "${SIGNKEY_HELPER_PID:-}"
    369 do
    370     if [ -n "$pid" ]
    371     then
    372         kill -TERM "$pid" 2> /dev/null || true
    373         wait "$pid" 2> /dev/null || true
    374     fi
    375 done
    376 exit_cleanup
    377 unset SETUP_PID
    378 
    379 
    380 # Where do we write the result?
    381 export BASEDB=${1:-"revoke-basedb"}
    382 
    383 
    384 # Dump database
    385 mkdir -p "$(dirname "$BASEDB")"
    386 echo "Dumping database ${BASEDB}.sql"
    387 pg_dump -O "auditor-basedb" | sed -e '/AS integer/d' > "${BASEDB}.sql"
    388 cp "${CONF}" "${BASEDB}.conf"
    389 cp "$(taler-exchange-config -c "${CONF}" -s exchange-offline -o MASTER_PRIV_FILE -f)" "${BASEDB}.mpriv"
    390 
    391 # clean up
    392 echo -n "Final clean up ..."
    393 dropdb "auditor-basedb"
    394 echo " DONE"
    395 
    396 echo "====================================="
    397 echo "Finished generation of ${BASEDB}.sql"
    398 echo "====================================="
    399 
    400 exit 0