exchange

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

commit ace816572e8ae465b168db9214c2c7f895f76b88
parent d068ebf661c0cf02cde2107dd5344318d7c8f18d
Author: Özgür Kesim <oec@codeblau.de>
Date:   Mon, 31 Mar 2025 18:03:02 +0200

[auditor] wip: adapt auditor to use and check new withdraw table

Diffstat:
Msrc/auditor/report-lib.c | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/auditor/report-lib.h | 12++++++++++++
Msrc/auditor/taler-helper-auditor-coins.c | 2+-
Msrc/auditor/taler-helper-auditor-reserves.c | 192++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/auditor/taler-helper-auditor-transfer.c | 2+-
Msrc/auditor/test-auditor.sh | 4++--
6 files changed, 251 insertions(+), 79 deletions(-)

diff --git a/src/auditor/report-lib.c b/src/auditor/report-lib.c @@ -77,6 +77,26 @@ struct GNUNET_TIME_Absolute start_time; */ static struct GNUNET_CONTAINER_MultiHashMap *denominations; +/** + * Results about denominations, cached per-transaction, maps row/serial ID's + * to `const struct TALER_EXCHANGEDB_DenominationKeyInformation`. + */ +static struct GNUNET_CONTAINER_MultiUuidmap *denominations_by_serial; + +/** + * Helper to convert a serial/row id to a uuid for the lookup + * in a uuid hash table + */ +static struct GNUNET_Uuid +serial_to_uuid ( + uint64_t serial) +{ + struct GNUNET_Uuid uuid; + uuid.value[0] = serial; + uuid.value[1] = serial >> 32; + return uuid; +} + /** * Function called with the results of iterate_denomination_info(), @@ -84,12 +104,14 @@ static struct GNUNET_CONTAINER_MultiHashMap *denominations; * to our hash table. * * @param cls closure, NULL + * @param denom_serial table row of the denomaination * @param denom_pub public key, sometimes NULL (!) * @param issue issuing information with value, fees and other info about the denomination. */ static void add_denomination ( void *cls, + uint64_t denom_serial, const struct TALER_DenominationPublicKey *denom_pub, const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue) { @@ -118,6 +140,7 @@ add_denomination ( #endif { struct TALER_EXCHANGEDB_DenominationKeyInformation *i; + struct GNUNET_Uuid uuid; i = GNUNET_new (struct TALER_EXCHANGEDB_DenominationKeyInformation); *i = *issue; @@ -126,6 +149,12 @@ add_denomination ( &issue->denom_hash.hash, i, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + uuid = serial_to_uuid (denom_serial); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multiuuidmap_put (denominations_by_serial, + &uuid, + i, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); } } @@ -141,6 +170,10 @@ TALER_ARL_get_denomination_info_by_hash ( { denominations = GNUNET_CONTAINER_multihashmap_create (256, GNUNET_NO); + if (NULL == denominations_by_serial) + denominations_by_serial = GNUNET_CONTAINER_multiuuidmap_create (256, + GNUNET_NO); + qs = TALER_ARL_edb->iterate_denomination_info (TALER_ARL_edb->cls, &add_denomination, NULL); @@ -166,9 +199,11 @@ TALER_ARL_get_denomination_info_by_hash ( /* maybe database changed since we last iterated, give it one more shot */ { struct TALER_EXCHANGEDB_DenominationKeyInformation issue; + uint64_t denom_serial; qs = TALER_ARL_edb->get_denomination_info (TALER_ARL_edb->cls, dh, + &denom_serial, &issue); if (qs <= 0) { @@ -179,7 +214,9 @@ TALER_ARL_get_denomination_info_by_hash ( TALER_B2S (dh)); return qs; } + add_denomination (NULL, + denom_serial, NULL, &issue); } @@ -204,6 +241,87 @@ TALER_ARL_get_denomination_info_by_hash ( enum GNUNET_DB_QueryStatus +TALER_ARL_get_denomination_info_by_serial ( + uint64_t denom_serial, + const struct TALER_EXCHANGEDB_DenominationKeyInformation **issuep) +{ + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_Uuid uuid = serial_to_uuid (denom_serial); + + if (NULL == denominations_by_serial) + { + denominations_by_serial = GNUNET_CONTAINER_multiuuidmap_create (256, + GNUNET_NO); + if (NULL == denominations) + denominations = GNUNET_CONTAINER_multihashmap_create (256, + GNUNET_NO); + + qs = TALER_ARL_edb->iterate_denomination_info (TALER_ARL_edb->cls, + &add_denomination, + NULL); + if (0 > qs) + { + GNUNET_break (0); + *issuep = NULL; + return qs; + } + } + { + const struct TALER_EXCHANGEDB_DenominationKeyInformation *i; + + i = GNUNET_CONTAINER_multiuuidmap_get (denominations_by_serial, + &uuid); + if (NULL != i) + { + /* cache hit */ + *issuep = i; + return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + } + } + /* maybe database changed since we last iterated, give it one more shot */ + { + struct TALER_EXCHANGEDB_DenominationKeyInformation issue; + + qs = TALER_ARL_edb->get_denomination_by_serial (TALER_ARL_edb->cls, + denom_serial, + &issue); + if (qs <= 0) + { + GNUNET_break (qs >= 0); + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Denomination with serial %lu not found\n", + denom_serial); + return qs; + } + + add_denomination (NULL, + denom_serial, + NULL, + &issue); + } + + { + const struct TALER_EXCHANGEDB_DenominationKeyInformation *i; + + i = GNUNET_CONTAINER_multiuuidmap_get (denominations_by_serial, + &uuid); + if (NULL != i) + { + /* cache hit */ + *issuep = i; + return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + } + } + /* We found more keys, but not the denomination we are looking for :-( */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Denomination with serial %lu not found\n", + denom_serial); + return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; +} + + +enum GNUNET_DB_QueryStatus TALER_ARL_get_denomination_info ( const struct TALER_DenominationPublicKey *denom_pub, const struct TALER_EXCHANGEDB_DenominationKeyInformation **issue, diff --git a/src/auditor/report-lib.h b/src/auditor/report-lib.h @@ -144,6 +144,18 @@ TALER_ARL_get_denomination_info_by_hash ( const struct TALER_DenominationHashP *dh, const struct TALER_EXCHANGEDB_DenominationKeyInformation **issuep); +/** + * Obtain information about a @a denomination by its serial + * + * @param serial row id of the denomination to look up + * @param[out] issuep set to detailed information about @a denom_pub, NULL if not found, must + * NOT be freed by caller + * @return transaction status code + */ +enum GNUNET_DB_QueryStatus +TALER_ARL_get_denomination_info_by_serial ( + uint64_t serial, + const struct TALER_EXCHANGEDB_DenominationKeyInformation **issuep); /** * Obtain information about a @a denom_pub. diff --git a/src/auditor/taler-helper-auditor-coins.c b/src/auditor/taler-helper-auditor-coins.c @@ -965,7 +965,7 @@ cleanup_denomination (void *cls, * we now have additional coins that have been issued. * * Note that the signature was already checked in - * taler-helper-auditor-reserves.c::#handle_reserve_out(), so we do not check + * taler-helper-auditor-reserves.c::#handle_withdrawals(), so we do not check * it again here. * * @param cls our `struct CoinContext` diff --git a/src/auditor/taler-helper-auditor-reserves.c b/src/auditor/taler-helper-auditor-reserves.c @@ -58,7 +58,7 @@ static struct GNUNET_TIME_Relative idle_reserve_expiration_time; * Checkpointing our progress for reserves. */ static TALER_ARL_DEF_PP (reserves_reserve_in_serial_id); -static TALER_ARL_DEF_PP (reserves_reserve_out_serial_id); +static TALER_ARL_DEF_PP (reserves_withdraw_serial_id); static TALER_ARL_DEF_PP (reserves_reserve_recoup_serial_id); static TALER_ARL_DEF_PP (reserves_reserve_open_serial_id); static TALER_ARL_DEF_PP (reserves_reserve_close_serial_id); @@ -255,7 +255,7 @@ struct ReserveSummary /** * Sum of all outgoing transfers during this transaction (includes fees). - * Updated only in #handle_reserve_out(). + * Updated only in #handle_withdrawals(). */ struct TALER_Amount total_out; @@ -513,8 +513,13 @@ handle_reserve_in ( * @param cls our `struct ReserveContext` * @param rowid unique serial ID for the refresh session in our DB * @param num_evs number of elements in @e h_blind_evs - * @param h_blind_evs array @e num_evs of blinded hash of the coin's public keys - * @param denom_pub public denomination key of the deposited coin + * @param h_blind_evs array @e num_evs of blinded hashes of the coin's public keys + * @param denom_serials array @e num_evs of serial ID's of denominations in our DB + * @param h_commitment hash of the commitment of the withdraw + * @param h_planchets running hash over all hashes of blinded planchets in the original withdraw request + * @param age_proof_required true if the withdraw request required an age proof. + * @param max_age if @e age_proof_required is true, the maximum age that was set on the coins. + * @param noreveal_index if @e age_proof_required is true, the index that was returned by the exchange for the reveal phase. * @param reserve_pub public key of the reserve * @param reserve_sig signature over the withdraw operation * @param execution_date when did the wallet withdraw the coin @@ -522,12 +527,17 @@ handle_reserve_in ( * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop */ static enum GNUNET_GenericReturnValue -handle_reserve_out ( +handle_withdrawals ( void *cls, uint64_t rowid, size_t num_evs, const struct TALER_BlindedCoinHashP *h_blind_evs, - const struct TALER_DenominationPublicKey *denom_pub, + const uint64_t *denom_serials, + const struct TALER_WithdrawCommitmentHashP *h_commitment, + const struct TALER_HashBlindedPlanchetsP *h_planchets, + bool age_proof_required, + uint8_t max_age, + uint8_t noreveal_index, const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReserveSignatureP *reserve_sig, struct GNUNET_TIME_Timestamp execution_date, @@ -536,80 +546,115 @@ handle_reserve_out ( struct ReserveContext *rc = cls; struct ReserveSummary *rs; const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue; + struct TALER_Amount auditor_amount; + struct TALER_Amount auditor_fee; struct TALER_Amount auditor_amount_with_fee; enum GNUNET_DB_QueryStatus qs; - struct TALER_DenominationHashP h_denom_pub; /* should be monotonically increasing */ - GNUNET_assert (rowid >= TALER_ARL_USE_PP (reserves_reserve_out_serial_id)); - TALER_ARL_USE_PP (reserves_reserve_out_serial_id) = rowid + 1; - - /* lookup denomination pub data (make sure denom_pub is valid, establish fees); - initializes wsrd.h_denomination_pub! */ - qs = TALER_ARL_get_denomination_info (denom_pub, - &issue, - &h_denom_pub); - if (0 > qs) - { - 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 %s (%s) from database!\n", - TALER_B2S (denom_pub), - TALER_amount2s (amount_with_fee)); - rc->qs = qs; - return GNUNET_SYSERR; - } - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) - { - report_row_inconsistency ("withdraw", - rowid, - "denomination key not found"); - if (global_qs < 0) - return GNUNET_SYSERR; - return GNUNET_OK; - } - - /* check that execution date is within withdraw range for denom_pub */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Checking withdraw timing: %llu, expire: %llu, timing: %llu\n", - (unsigned long long) issue->start.abs_time.abs_value_us, - (unsigned long long) issue->expire_withdraw.abs_time.abs_value_us, - (unsigned long long) execution_date.abs_time.abs_value_us); - if (GNUNET_TIME_timestamp_cmp (issue->start, - >, - execution_date) || - GNUNET_TIME_timestamp_cmp (issue->expire_withdraw, - <, - execution_date)) - { - struct TALER_AUDITORDB_DenominationKeyValidityWithdrawInconsistency dkvwi ={ - .problem_row_id = rowid, - .execution_date = execution_date.abs_time, - .denompub_h = *&h_denom_pub, - .reserve_pub = *reserve_pub - }; + GNUNET_assert (rowid >= TALER_ARL_USE_PP (reserves_withdraw_serial_id)); + TALER_ARL_USE_PP (reserves_withdraw_serial_id) = rowid + 1; - qs = - TALER_ARL_adb->insert_denomination_key_validity_withdraw_inconsistency ( - TALER_ARL_adb->cls, - &dkvwi); + GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TALER_ARL_currency, + &auditor_amount)); + GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TALER_ARL_currency, + &auditor_fee)); + GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TALER_ARL_currency, + &auditor_amount_with_fee)); - if (qs < 0) + for (size_t i = 0; i < num_evs; i++) + { + /* lookup denomination pub data (make sure denom_pub is valid, establish fees); + initializes wsrd.h_denomination_pub! */ + qs = TALER_ARL_get_denomination_info_by_serial (denom_serials[i], + &issue); + if (0 > qs) { 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], + GNUNET_h2s (&h_commitment->hash)); rc->qs = qs; return GNUNET_SYSERR; } + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + { + report_row_inconsistency ("withdraw", + rowid, + "denomination key not found"); + if (global_qs < 0) + return GNUNET_SYSERR; + return GNUNET_OK; + } + + /* check that execution date is within withdraw range for denom_pub */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Checking withdraw timing: %llu, expire: %llu, timing: %llu\n", + (unsigned long long) issue->start.abs_time.abs_value_us, + (unsigned long + long) issue->expire_withdraw.abs_time.abs_value_us, + (unsigned long long) execution_date.abs_time.abs_value_us); + if (GNUNET_TIME_timestamp_cmp (issue->start, + >, + execution_date) || + GNUNET_TIME_timestamp_cmp (issue->expire_withdraw, + <, + execution_date)) + { + struct TALER_AUDITORDB_DenominationKeyValidityWithdrawInconsistency + dkvwi ={ + .problem_row_id = rowid, + .execution_date = execution_date.abs_time, + .denompub_h = issue->denom_hash, + .reserve_pub = *reserve_pub + }; + + qs = + TALER_ARL_adb->insert_denomination_key_validity_withdraw_inconsistency ( + TALER_ARL_adb->cls, + &dkvwi); + + if (qs < 0) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + rc->qs = qs; + return GNUNET_SYSERR; + } + } + TALER_ARL_amount_add (&auditor_amount, + &auditor_amount, + &issue->value); + TALER_ARL_amount_add (&auditor_fee, + &auditor_fee, + &issue->fees.withdraw); + { + struct TALER_Amount amount_with_fee; + + TALER_ARL_amount_add (&amount_with_fee, + &issue->value, + &issue->fees.withdraw); + TALER_ARL_amount_add (&auditor_amount_with_fee, + &auditor_amount_with_fee, + &amount_with_fee); + } } /* check reserve_sig (first: setup remaining members of wsrd) */ if (GNUNET_OK != - TALER_wallet_withdraw_verify_pre26 (&h_denom_pub, - amount_with_fee, - &h_blind_evs[0], - reserve_pub, - reserve_sig)) + TALER_wallet_withdraw_verify ( + &auditor_amount, + &auditor_fee, + h_planchets, + age_proof_required + ? &issue->age_mask + : NULL, + age_proof_required + ? max_age + : 0, + reserve_pub, + reserve_sig)) { struct TALER_AUDITORDB_BadSigLosses bsl = { .problem_row_id = rowid, @@ -634,9 +679,6 @@ handle_reserve_out ( return GNUNET_OK; /* exit function here, we cannot add this to the legitimate withdrawals */ } - TALER_ARL_amount_add (&auditor_amount_with_fee, - &issue->value, - &issue->fees.withdraw); if (0 != TALER_amount_cmp (&auditor_amount_with_fee, amount_with_fee)) @@ -1754,7 +1796,7 @@ analyze_reserves (void *cls) qs = TALER_ARL_adb->get_auditor_progress ( TALER_ARL_adb->cls, TALER_ARL_GET_PP (reserves_reserve_in_serial_id), - TALER_ARL_GET_PP (reserves_reserve_out_serial_id), + TALER_ARL_GET_PP (reserves_withdraw_serial_id), TALER_ARL_GET_PP (reserves_reserve_recoup_serial_id), TALER_ARL_GET_PP (reserves_reserve_open_serial_id), TALER_ARL_GET_PP (reserves_reserve_close_serial_id), @@ -1779,7 +1821,7 @@ analyze_reserves (void *cls) (unsigned long long) TALER_ARL_USE_PP ( reserves_reserve_in_serial_id), (unsigned long long) TALER_ARL_USE_PP ( - reserves_reserve_out_serial_id), + reserves_withdraw_serial_id), (unsigned long long) TALER_ARL_USE_PP ( reserves_reserve_recoup_serial_id), (unsigned long long) TALER_ARL_USE_PP ( @@ -1827,8 +1869,8 @@ analyze_reserves (void *cls) CHECK_DB (); qs = TALER_ARL_edb->select_withdrawals_above_serial_id ( TALER_ARL_edb->cls, - TALER_ARL_USE_PP (reserves_reserve_out_serial_id), - &handle_reserve_out, + TALER_ARL_USE_PP (reserves_withdraw_serial_id), + &handle_withdrawals, &rc); CHECK_DB (); qs = TALER_ARL_edb->select_recoup_above_serial_id ( @@ -1928,7 +1970,7 @@ analyze_reserves (void *cls) qs = TALER_ARL_adb->insert_auditor_progress ( TALER_ARL_adb->cls, TALER_ARL_SET_PP (reserves_reserve_in_serial_id), - TALER_ARL_SET_PP (reserves_reserve_out_serial_id), + TALER_ARL_SET_PP (reserves_withdraw_serial_id), TALER_ARL_SET_PP (reserves_reserve_recoup_serial_id), TALER_ARL_SET_PP (reserves_reserve_open_serial_id), TALER_ARL_SET_PP (reserves_reserve_close_serial_id), @@ -1946,7 +1988,7 @@ analyze_reserves (void *cls) qs = TALER_ARL_adb->update_auditor_progress ( TALER_ARL_adb->cls, TALER_ARL_SET_PP (reserves_reserve_in_serial_id), - TALER_ARL_SET_PP (reserves_reserve_out_serial_id), + TALER_ARL_SET_PP (reserves_withdraw_serial_id), TALER_ARL_SET_PP (reserves_reserve_recoup_serial_id), TALER_ARL_SET_PP (reserves_reserve_open_serial_id), TALER_ARL_SET_PP (reserves_reserve_close_serial_id), @@ -1967,7 +2009,7 @@ analyze_reserves (void *cls) (unsigned long long) TALER_ARL_USE_PP ( reserves_reserve_in_serial_id), (unsigned long long) TALER_ARL_USE_PP ( - reserves_reserve_out_serial_id), + reserves_withdraw_serial_id), (unsigned long long) TALER_ARL_USE_PP ( reserves_reserve_recoup_serial_id), (unsigned long long) TALER_ARL_USE_PP ( diff --git a/src/auditor/taler-helper-auditor-transfer.c b/src/auditor/taler-helper-auditor-transfer.c @@ -156,7 +156,7 @@ import_wire_missing_cb ( wire_target_h_payto, total_amount, deadline); - if (0 < qs) + if (0 > qs) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); wc->err = qs; diff --git a/src/auditor/test-auditor.sh b/src/auditor/test-auditor.sh @@ -462,10 +462,10 @@ function call_endpoint() { if [ -n "${2+x}" ] then 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}" - echo -n "CD... " + echo "endpoint ${1} called (with balance_key)... " else curl -s -H "Accept: application/json" -H "Authorization: Bearer ${TALER_AUDITOR_TOKEN}" -o "${MY_TMP_DIR}/${1}.json" "localhost:8083/monitoring/${1}?limit=50" - echo -n "CD... " + echo "endpoint ${1} called... " fi }