exchange

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

commit 7d866a446d61d40781a6d5c00300032e71519f99
parent 593fe175f19413412c152018942ac0d3cc8d2b19
Author: Christian Grothoff <christian@grothoff.org>
Date:   Tue, 27 May 2025 22:42:18 +0200

misc. fixes around #9900 auditor and sync tests

Diffstat:
Msrc/auditor/Makefile.am | 2--
Msrc/auditor/generate-revoke-basedb.sh | 46+++++++++++++++++++++++-----------------------
Msrc/auditor/taler-auditor-sync.c | 1+
Msrc/auditor/taler-helper-auditor-reserves.c | 35++++++++++++++++++++++++++++-------
Msrc/auditor/test-auditor.sh | 12+++---------
Msrc/auditor/test-sync.sh | 2+-
Msrc/exchangedb/pg_insert_records_by_table.c | 7++++---
Msrc/exchangedb/pg_lookup_records_by_table.c | 80++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/include/taler_exchangedb_plugin.h | 2+-
9 files changed, 110 insertions(+), 77 deletions(-)

diff --git a/src/auditor/Makefile.am b/src/auditor/Makefile.am @@ -255,11 +255,9 @@ check_SCRIPTS = \ AM_TESTS_ENVIRONMENT=export TALER_EXCHANGE_PREFIX=$${TALER_EXCHANGE_PREFIX:-@libdir@};export PATH=$${TALER_EXCHANGE_PREFIX:-@prefix@}/bin:$$PATH;export TALER_AUDITOR_PREFIX=$${TALER_AUDITOR_PREFIX:-@libdir@}; #TESTS = \ -# test-revocation.sh \ # test-sync.sh \ # test-auditor.sh - EXTRA_DIST = \ taler-helper-auditor-render.py \ auditor.conf \ diff --git a/src/auditor/generate-revoke-basedb.sh b/src/auditor/generate-revoke-basedb.sh @@ -14,8 +14,6 @@ echo -n "Testing for curl ..." curl --help >/dev/null </dev/null || exit_skip " MISSING" echo " FOUND" -CONF="generate-auditor-basedb.conf" - # reset database echo -n "Reset 'auditor-basedb' database ..." dropdb "auditor-basedb" >/dev/null 2>/dev/null || true @@ -23,9 +21,10 @@ createdb "auditor-basedb" || exit_skip "Could not create database '$BASEDB'" echo " DONE" # Launch exchange, merchant and bank. -setup -c "$CONF" \ +setup -c generate-auditor-basedb.conf \ -abemw \ -d "iban" +CONF="generate-auditor-basedb.conf.edited" # obtain key configuration data EXCHANGE_URL=$(taler-exchange-config -c "$CONF" -s EXCHANGE -o BASE_URL) @@ -78,17 +77,18 @@ export COINS=$(taler-wallet-cli --wallet-db="$WALLET_DB" advanced dump-coins) echo -n "COINS are:" echo "$COINS" +export COINS # Find coin we want to revoke -export rc=$(echo "$COINS" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:2"))][0] | .coin_pub') +export rc=$(echo "$COINS" | jq -r '[.coins[] | select((.denomValue == "TESTKUDOS:2"))][0] | .coinPub') # Find the denom -export rd=$(echo "$COINS" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:2"))][0] | .denom_pub_hash') +export rd=$(echo "$COINS" | jq -r '[.coins[] | select((.denomValue == "TESTKUDOS:2"))][0] | .denomPubHash') echo -n "Revoking denomination ${rd} (to affect coin ${rc}) ..." # Find all other coins, which will be suspended -export susp=$(echo "$COINS" | jq --arg rc "$rc" '[.coins[] | select(.coin_pub != $rc) | .coin_pub]') +export susp=$(echo "$COINS" | jq --arg rc "$rc" '[.coins[] | select(.coinPub != $rc) | .coinPub]') # Do the revocation taler-exchange-offline \ - -c $CONF \ + -c "$CONF" \ revoke-denomination "${rd}" \ upload \ &> taler-exchange-offline-revoke.log @@ -99,7 +99,7 @@ sleep 1 # Give exchange time to create replacmenent key # Re-sign replacement keys taler-auditor-offline \ - -c $CONF \ + -c "$CONF" \ download \ sign \ upload \ @@ -147,29 +147,29 @@ taler-wallet-cli \ echo "Purchase with recoup'ed coin (via reserve) done" # Find coin we want to refresh, then revoke -export rrc=$(echo "$coins" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:5"))][0] | .coin_pub') +export rrc=$(echo "$coins" | jq -r '[.coins[] | select((.denomValue == "TESTKUDOS:5"))][0] | .coinPub') # Find the denom -export zombie_denom=$(echo "$coins" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:5"))][0] | .denom_pub_hash') +export zombie_denom=$(echo "$coins" | jq -r '[.coins[] | select((.denomValue == "TESTKUDOS:5"))][0] | .denomPubHash') echo "Will refresh coin ${rrc} of denomination ${zombie_denom}" # Find all other coins, which will be suspended -export susp=$(echo "$coins" | jq --arg rrc "$rrc" '[.coins[] | select(.coin_pub != $rrc) | .coin_pub]') +export susp=$(echo "$coins" | jq --arg rrc "$rrc" '[.coins[] | select(.coinPub != $rrc) | .coinPub]') # Travel into the future! (must match DURATION_WITHDRAW option) export TIMETRAVEL="--timetravel=604800000000" echo "Launching exchange 1 week in the future" -kill -TERM $EXCHANGE_PID -kill -TERM $RSA_DENOM_HELPER_PID -kill -TERM $CS_DENOM_HELPER_PID -kill -TERM $SIGNKEY_HELPER_PID -taler-exchange-secmod-eddsa $TIMETRAVEL -c $CONF 2> ${MY_TMP_DIR}/taler-exchange-secmod-eddsa.log & +kill -TERM "$EXCHANGE_PID" +kill -TERM "$RSA_DENOM_HELPER_PID" +kill -TERM "$CS_DENOM_HELPER_PID" +kill -TERM "$SIGNKEY_HELPER_PID" +taler-exchange-secmod-eddsa $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-secmod-eddsa.log" & SIGNKEY_HELPER_PID=$! -taler-exchange-secmod-rsa $TIMETRAVEL -c $CONF 2> ${MY_TMP_DIR}/taler-exchange-secmod-rsa.log & +taler-exchange-secmod-rsa $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-secmod-rsa.log" & RSA_DENOM_HELPER_PID=$! -taler-exchange-secmod-cs $TIMETRAVEL -c $CONF 2> ${MY_TMP_DIR}/taler-exchange-secmod-cs.log & +taler-exchange-secmod-cs $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-secmod-cs.log" & CS_DENOM_HELPER_PID=$! -taler-exchange-httpd $TIMETRAVEL -c $CONF 2> ${MY_TMP_DIR}/taler-exchange-httpd.log & +taler-exchange-httpd $TIMETRAVEL -c "$CONF" 2> "${MY_TMP_DIR}/taler-exchange-httpd.log" & export EXCHANGE_PID=$! # Wait for exchange to be available @@ -196,22 +196,22 @@ taler-wallet-cli \ run-until-done # Update our list of the coins -export coins=$(taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB advanced dump-coins) +export coins=$(taler-wallet-cli "$TIMETRAVEL" --wallet-db="$WALLET_DB" advanced dump-coins) # Find resulting refreshed coin export freshc=$(echo "$coins" | jq -r --arg rrc "$rrc" \ - '[.coins[] | select((.refresh_parent_coin_pub == $rrc) and .denom_value == "TESTKUDOS:0.1")][0] | .coin_pub' + '[.coins[] | select((.refreshParentCoinPub == $rrc) and .denomValue == "TESTKUDOS:0.1")][0] | .coinPub' ) # Find the denom of freshc export fresh_denom=$(echo "$coins" | jq -r --arg rrc "$rrc" \ - '[.coins[] | select((.refresh_parent_coin_pub == $rrc) and .denom_value == "TESTKUDOS:0.1")][0] | .denom_pub_hash' + '[.coins[] | select((.refreshParentCoinPub == $rrc) and .denomValue == "TESTKUDOS:0.1")][0] | .denomPubHash' ) echo "Coin ${freshc} of denomination ${fresh_denom} is the result of the refresh" # Find all other coins, which will be suspended -export susp=$(echo "$coins" | jq --arg freshc "$freshc" '[.coins[] | select(.coin_pub != $freshc) | .coin_pub]') +export susp=$(echo "$coins" | jq --arg freshc "$freshc" '[.coins[] | select(.coinPub != $freshc) | .coinPub]') # Do the revocation of freshc diff --git a/src/auditor/taler-auditor-sync.c b/src/auditor/taler-auditor-sync.c @@ -91,6 +91,7 @@ struct Table static struct Table tables[] = { { .rt = TALER_EXCHANGEDB_RT_DENOMINATIONS}, { .rt = TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS}, + { .rt = TALER_EXCHANGEDB_RT_KYC_TARGETS}, { .rt = TALER_EXCHANGEDB_RT_WIRE_TARGETS}, { .rt = TALER_EXCHANGEDB_RT_LEGITIMIZATION_MEASURES}, { .rt = TALER_EXCHANGEDB_RT_LEGITIMIZATION_OUTCOMES}, diff --git a/src/auditor/taler-helper-auditor-reserves.c b/src/auditor/taler-helper-auditor-reserves.c @@ -549,6 +549,9 @@ handle_withdrawals ( enum GNUNET_DB_QueryStatus qs; /* should be monotonically increasing */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Analyzing withdrawal row %llu\n", + (unsigned long long) rowid); GNUNET_assert (rowid >= TALER_ARL_USE_PP (reserves_withdraw_serial_id)); TALER_ARL_USE_PP (reserves_withdraw_serial_id) = rowid + 1; @@ -570,14 +573,17 @@ handle_withdrawals ( GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); if (GNUNET_DB_STATUS_HARD_ERROR == qs) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Hard database error trying to get denomination by serial %lu (%s) from database!\n", - denom_serials[i], + "Hard database error trying to get denomination by serial %llu (%s) from database!\n", + (unsigned long long) denom_serials[i], GNUNET_h2s (&h_planchets->hash)); rc->qs = qs; return GNUNET_SYSERR; } if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Denomination #%llu not found\n", + (unsigned long long) denom_serials[i]); report_row_inconsistency ("withdraw", rowid, "denomination key not found"); @@ -585,6 +591,10 @@ handle_withdrawals ( return GNUNET_SYSERR; return GNUNET_OK; } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Analyzing withdrawn denomination #%llu (%s)\n", + (unsigned long long) denom_serials[i], + TALER_amount2s (&issue->value)); /* check that execution date is within withdraw range for denom_pub */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -608,6 +618,9 @@ handle_withdrawals ( .reserve_pub = *reserve_pub }; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Withdraw outside of denomination #%llu validity period detected\n", + (unsigned long long) denom_serials[i]); qs = TALER_ARL_adb->insert_denomination_key_validity_withdraw_inconsistency ( TALER_ARL_adb->cls, @@ -620,6 +633,9 @@ handle_withdrawals ( return GNUNET_SYSERR; } } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Adding withdraw fee of denomination (%s)\n", + TALER_amount2s (&issue->fees.withdraw)); TALER_ARL_amount_add (&auditor_amount, &auditor_amount, &issue->value); @@ -646,11 +662,11 @@ handle_withdrawals ( h_planchets, blinding_seed, age_proof_required - ? &issue->age_mask - : NULL, + ? &issue->age_mask + : NULL, age_proof_required - ? max_age - : 0, + ? max_age + : 0, reserve_pub, reserve_sig)) { @@ -661,10 +677,12 @@ handle_withdrawals ( .operation_specific_pub = reserve_pub->eddsa_pub }; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Withdraw signature invalid (row #%llu)\n", + (unsigned long long) rowid); qs = TALER_ARL_adb->insert_bad_sig_losses ( TALER_ARL_adb->cls, &bsl); - if (qs < 0) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); @@ -681,6 +699,9 @@ handle_withdrawals ( TALER_amount_cmp (&auditor_amount_with_fee, amount_with_fee)) { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Withdraw fee inconsistent (row #%llu)\n", + (unsigned long long) rowid); report_row_inconsistency ("withdraw", rowid, "amount with fee from exchange does not match denomination value plus fee"); diff --git a/src/auditor/test-auditor.sh b/src/auditor/test-auditor.sh @@ -1995,22 +1995,16 @@ function test_27() { function test_28() { echo "===========28: withdraw fee inconsistency =================" - echo "UPDATE exchange.denominations SET fee_withdraw.frac=5000000 WHERE (coin).val=1;" | psql -Aqt "$DB" + echo "UPDATE exchange.withdraw SET amount_with_fee.val=(amount_with_fee).val+1 WHERE withdraw_id=1;" | psql -Aqt "$DB" run_audit check_auditor_running echo -n "Testing inconsistency detection... " - check_not_balance \ - "total_balance_summary_delta_minus" \ - "TESTKUDOS:0" \ - "Reported total amount wrong" - echo -n "Checking report that delta was profitable... " check_report \ - "amount-arithmetic-inconsistency" \ - "profitable" "true" + "row-inconsistency" \ + "row_table" "withdraw" # Undo - echo "UPDATE exchange.denominations SET fee_withdraw.frac=2000000 WHERE (coin).val=1;" | psql -Aqt "$DB" full_reload } diff --git a/src/auditor/test-sync.sh b/src/auditor/test-sync.sh @@ -117,7 +117,7 @@ function check_with_database() -d test-sync-out.conf -t # cs_nonce_locks excluded: no point - for table in denominations denomination_revocations wire_targets reserves reserves_in reserves_close reserves_open_requests reserves_open_deposits reserves_out auditors auditor_denom_sigs exchange_sign_keys signkey_revocations known_coins refresh_commitments refresh_revealed_coins refresh_transfer_keys batch_deposits coin_deposits refunds wire_out aggregation_tracking wire_fee recoup recoup_refresh extensions policy_details policy_fulfillments purse_requests purse_decision purse_merges purse_deposits account_merges history_requests close_requests wads_out wad_out_entries wads_in wad_in_entries profit_Drains aml_staff purse_deletion age_withdraw legitimization_measures legitimization_outcomes legitimization_processes kyc_attributes aml_history kyc_events kycauths_in + for table in denominations denomination_revocations kyc_targets wire_targets reserves reserves_in reserves_close reserves_open_requests reserves_open_deposits withdraw auditors auditor_denom_sigs exchange_sign_keys signkey_revocations known_coins refresh_commitments refresh_revealed_coins refresh_transfer_keys batch_deposits coin_deposits refunds wire_out aggregation_tracking wire_fee recoup recoup_refresh extensions policy_details policy_fulfillments purse_requests purse_decision purse_merges purse_deposits account_merges history_requests close_requests wads_out wad_out_entries wads_in wad_in_entries profit_drains aml_staff purse_deletion age_withdraw legitimization_measures legitimization_outcomes legitimization_processes kyc_attributes aml_history kyc_events kycauths_in do echo -n "." CIN=$(echo "SELECT COUNT(*) FROM exchange.$table" | psql talercheck-in -Aqt) diff --git a/src/exchangedb/pg_insert_records_by_table.c b/src/exchangedb/pg_insert_records_by_table.c @@ -235,7 +235,7 @@ irbt_cb_table_kyc_targets (struct PostgresClosure *pg, ",target_pub" ",is_wallet" ") VALUES " - "($1, $2, $3, $4,);"); + "($1, $2, $3, $4, $5);"); return GNUNET_PQ_eval_prepared_non_select (pg->conn, "insert_into_table_kyc_targets", params); @@ -2225,11 +2225,12 @@ irbt_cb_table_withdraw ( GNUNET_PQ_query_param_end }; + // FIXME: rather wrong, misses fields, etc. PREPARE (pg, "insert_into_table_withdraw", "INSERT INTO withdraw" "(withdraw_id" - ",h_planchets" + ",planchets_h" ",amount_with_fee" ",max_age" ",noreveal_index" @@ -2237,7 +2238,7 @@ irbt_cb_table_withdraw ( ",reserve_sig" ",execution_date" ",blinding_seed" - ",cs_r_pubs" + ",cs_r_pubs" // FIXME: cs_r_values, ... ") VALUES " "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);"); return GNUNET_PQ_eval_prepared_non_select (pg->conn, diff --git a/src/exchangedb/pg_lookup_records_by_table.c b/src/exchangedb/pg_lookup_records_by_table.c @@ -2568,14 +2568,20 @@ lrbt_cb_table_withdraw (void *cls, "withdraw_id", &td.serial), GNUNET_PQ_result_spec_auto_from_type ( - "h_planchets", + "planchets_h", &td.details.withdraw.h_planchets), - TALER_PQ_RESULT_SPEC_AMOUNT ( - "amount_with_fee", - &td.details.withdraw.amount_with_fee), GNUNET_PQ_result_spec_timestamp ( "execution_date", &td.details.withdraw.execution_date), + TALER_PQ_RESULT_SPEC_AMOUNT ( + "amount_with_fee", + &td.details.withdraw.amount_with_fee), + GNUNET_PQ_result_spec_auto_from_type ( + "reserve_pub", + &td.details.withdraw.reserve_pub), + GNUNET_PQ_result_spec_auto_from_type ( + "reserve_sig", + &td.details.withdraw.reserve_sig), GNUNET_PQ_result_spec_allow_null ( GNUNET_PQ_result_spec_uint16 ( "max_age", @@ -2586,39 +2592,46 @@ lrbt_cb_table_withdraw (void *cls, "noreveal_index", &td.details.withdraw.noreveal_index), &no_noreveal_index), - GNUNET_PQ_result_spec_auto_from_type ( - "reserve_pub", - &td.details.withdraw.reserve_pub), - GNUNET_PQ_result_spec_auto_from_type ( - "reserve_sig", - &td.details.withdraw.reserve_sig), - GNUNET_PQ_result_spec_array_uint64 ( - pg->conn, - "denom_serials", - &td.details.withdraw.num_coins, - &td.details.withdraw.denominations_serials), - TALER_PQ_result_spec_array_blinded_coin_hash ( - pg->conn, - "h_blind_evs", - &num_h_coin_evs, - &td.details.withdraw.h_coin_evs), - TALER_PQ_result_spec_array_blinded_denom_sig ( - pg->conn, - "denom_sigs", - &num_sigs, - &td.details.withdraw.denom_sigs), + +#if FIXME_9900 + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_auto_from_type ( + "selected_h", + &td.details.withdraw.selected_h), + &td.details.withdraw.no_selected_h), +#endif + GNUNET_PQ_result_spec_allow_null ( GNUNET_PQ_result_spec_auto_from_type ( "blinding_seed", &td.details.withdraw.blinding_seed), &td.details.withdraw.no_blinding_seed), + + // FIXME: gone... + TALER_PQ_result_spec_array_blinded_coin_hash ( + pg->conn, + "h_blind_evs", + &num_h_coin_evs, + &td.details.withdraw.h_coin_evs), + GNUNET_PQ_result_spec_allow_null ( TALER_PQ_result_spec_array_cs_r_pub ( pg->conn, - "cs_r_pubs", + "cs_r_pubs", // FIXME: cs_r_values! &td.details.withdraw.num_cs_r_pubs, &td.details.withdraw.cs_r_pubs), &no_cs_r_pubs), + // FIXME: cs_r_choices missing! + GNUNET_PQ_result_spec_array_uint64 ( + pg->conn, + "denom_serials", + &td.details.withdraw.num_coins, + &td.details.withdraw.denominations_serials), + TALER_PQ_result_spec_array_blinded_denom_sig ( + pg->conn, + "denom_sigs", + &num_sigs, + &td.details.withdraw.denom_sigs), GNUNET_PQ_result_spec_end }; @@ -3628,14 +3641,19 @@ TEH_PG_lookup_records_by_table (void *cls, XPREPARE ("select_above_serial_by_table_withdraw", "SELECT" " withdraw_id" - ",h_planchets" + ",planchets_h" + ",execution_date" ",amount_with_fee" - ",max_age" - ",noreveal_index" - ",h_planchets" ",reserve_pub" ",reserve_sig" - ",execution_date" + ",max_age" + ",noreveal_index" + ",selected_h" + ",blinding_seed" + ",cs_r_values" + ",cs_r_choices" + ",denom_serials" + ",denom_sigs" " FROM withdraw" " WHERE withdraw_id > $1" " ORDER BY withdraw_id ASC;"); diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h @@ -281,8 +281,8 @@ enum TALER_EXCHANGEDB_ReplicatedTable { TALER_EXCHANGEDB_RT_DENOMINATIONS, TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS, - TALER_EXCHANGEDB_RT_WIRE_TARGETS, TALER_EXCHANGEDB_RT_KYC_TARGETS, + TALER_EXCHANGEDB_RT_WIRE_TARGETS, TALER_EXCHANGEDB_RT_RESERVES, TALER_EXCHANGEDB_RT_RESERVES_IN, TALER_EXCHANGEDB_RT_RESERVES_CLOSE,