diff options
author | Christian Grothoff <christian@grothoff.org> | 2022-06-05 14:07:23 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2022-06-05 14:07:23 +0200 |
commit | b9963f75255e416ca79b2f5c3081bde4ba78fab0 (patch) | |
tree | 9575e9558b6f8960798c09dec681dc277f96babc /src/lib/exchange_api_purse_create_with_deposit.c | |
parent | 6c81796d6f39e932d58b4fc1729b472d0e46e3d1 (diff) | |
download | exchange-b9963f75255e416ca79b2f5c3081bde4ba78fab0.tar.xz |
complete P2P/W2W conflict handling, deduplicate code across handlers
Diffstat (limited to 'src/lib/exchange_api_purse_create_with_deposit.c')
-rw-r--r-- | src/lib/exchange_api_purse_create_with_deposit.c | 203 |
1 files changed, 178 insertions, 25 deletions
diff --git a/src/lib/exchange_api_purse_create_with_deposit.c b/src/lib/exchange_api_purse_create_with_deposit.c index f21b7d312..f2d80b942 100644 --- a/src/lib/exchange_api_purse_create_with_deposit.c +++ b/src/lib/exchange_api_purse_create_with_deposit.c @@ -35,6 +35,33 @@ /** + * Information we track per deposited coin. + */ +struct Deposit +{ + /** + * Coin's public key. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * Signature made with the coin. + */ + struct TALER_CoinSpendSignatureP coin_sig; + + /** + * Coin's denomination. + */ + struct TALER_DenominationHashP h_denom_pub; + + /** + * How much did we say the coin contributed. + */ + struct TALER_Amount contribution; +}; + + +/** * @brief A purse create with deposit handle */ struct TALER_EXCHANGE_PurseCreateDepositHandle @@ -106,6 +133,16 @@ struct TALER_EXCHANGE_PurseCreateDepositHandle */ struct GNUNET_TIME_Timestamp purse_expiration; + /** + * Array of @e num_deposit deposits. + */ + struct Deposit *deposits; + + /** + * How many deposits did we make? + */ + unsigned int num_deposits; + }; @@ -128,8 +165,10 @@ handle_purse_create_deposit_finished (void *cls, .hr.reply = j, .hr.http_status = (unsigned int) response_code }; + const struct TALER_EXCHANGE_Keys *keys; pch->job = NULL; + keys = TALER_EXCHANGE_get_keys (pch->exchange); switch (response_code) { case 0: @@ -232,43 +271,151 @@ handle_purse_create_deposit_finished (void *cls, break; case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS: { -#if FIXME - struct TALER_Amount total; - struct TALER_DenominationHashP h_denom_pub; - const struct TALER_EXCHANGE_DenomPublicKey *dk = NULL; + struct TALER_Amount left; + struct TALER_CoinSpendPublicKeyP pcoin_pub; + bool found = false; - // FIXME: parse coin_pub - // FIXME: lookup dk for that coin from our deposits array! - - if (NULL == dk) + if (GNUNET_OK != + TALER_EXCHANGE_check_coin_amount_conflict_ ( + keys, + j, + &pcoin_pub, + &left)) { - /* not one of our coins */ GNUNET_break_op (0); dr.hr.http_status = 0; dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } + for (unsigned int i = 0; i<pch->num_deposits; i++) + { + struct Deposit *deposit = &pch->deposits[i]; + + if (0 != GNUNET_memcmp (&pcoin_pub, + &deposit->coin_pub)) + continue; + if (-1 != + TALER_amount_cmp (&left, + &deposit->contribution)) + { + /* Balance was sufficient after all; recoup MAY have still been possible */ + GNUNET_break_op (0); + continue; + } + if (GNUNET_OK != + TALER_EXCHANGE_check_coin_signature_conflict_ ( + j, + &deposit->coin_sig)) + { + GNUNET_break_op (0); + continue; + } + found = true; + break; + } + if (! found) + { + /* conflict is for a different coin! */ + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; + } + break; + } + case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY: + { + struct TALER_Amount left; + struct TALER_CoinSpendPublicKeyP pcoin_pub; + bool found = false; + if (GNUNET_OK != - TALER_EXCHANGE_verify_coin_history (dk, - pch->exchange->currency, - &coin_pub, - history, - &h_denom_pub, - &total)) + TALER_EXCHANGE_check_coin_amount_conflict_ ( + keys, + j, + &pcoin_pub, + &left)) { GNUNET_break_op (0); dr.hr.http_status = 0; dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } - // FIXME: check total is too high for the request... -#endif + for (unsigned int i = 0; i<pch->num_deposits; i++) + { + struct Deposit *deposit = &pch->deposits[i]; + + if (0 != + GNUNET_memcmp (&pcoin_pub, + &deposit->coin_pub)) + continue; + if (GNUNET_OK != + TALER_EXCHANGE_check_coin_denomination_conflict_ ( + j, + &deposit->h_denom_pub)) + { + /* Eh, same denomination, hence no conflict */ + GNUNET_break_op (0); + continue; + } + found = true; + } + if (! found) + { + /* conflict is for a different coin! */ + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; + } + /* meta data conflict is real! */ break; } case TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA: { - // FIXME! - break; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_CoinSpendSignatureP coin_sig; + bool found = false; + + if (GNUNET_OK != + TALER_EXCHANGE_check_purse_coin_conflict_ ( + &pch->purse_pub, + pch->exchange->url, + j, + &coin_pub, + &coin_sig)) + { + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; + } + for (unsigned int i = 0; i<pch->num_deposits; i++) + { + struct Deposit *deposit = &pch->deposits[i]; + + if (0 != + GNUNET_memcmp (&coin_pub, + &deposit->coin_pub)) + continue; + if (0 == + GNUNET_memcmp (&coin_sig, + &deposit->coin_sig)) + { + GNUNET_break_op (0); + continue; + } + found = true; + break; + } + if (! found) + { + /* conflict is for a different coin! */ + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; + } } case TALER_EC_EXCHANGE_PURSE_ECONTRACT_CONFLICTING_META_DATA: if (GNUNET_OK != @@ -408,6 +555,9 @@ TALER_EXCHANGE_purse_create_with_deposit ( GNUNET_free (pch); return NULL; } + pch->num_deposits = num_deposits; + pch->deposits = GNUNET_new_array (num_deposits, + struct Deposit); deposit_arr = json_array (); GNUNET_assert (NULL != deposit_arr); url = TEAH_path_to_url (exchange, @@ -418,9 +568,8 @@ TALER_EXCHANGE_purse_create_with_deposit ( for (unsigned int i = 0; i<num_deposits; i++) { const struct TALER_EXCHANGE_PurseDeposit *deposit = &deposits[i]; + struct Deposit *d = &pch->deposits[i]; json_t *jdeposit; - struct TALER_CoinSpendSignatureP coin_sig; - struct TALER_CoinSpendPublicKeyP coin_pub; #if FIXME_OEC struct TALER_AgeCommitmentHash agh; struct TALER_AgeCommitmentHash *aghp = NULL; @@ -441,14 +590,16 @@ TALER_EXCHANGE_purse_create_with_deposit ( return NULL; } #endif + d->contribution = deposit->amount; + d->h_denom_pub = deposit->h_denom_pub; GNUNET_CRYPTO_eddsa_key_get_public (&deposit->coin_priv.eddsa_priv, - &coin_pub.eddsa_pub); + &d->coin_pub.eddsa_pub); TALER_wallet_purse_deposit_sign ( url, &pch->purse_pub, &deposit->amount, &deposit->coin_priv, - &coin_sig); + &d->coin_sig); jdeposit = GNUNET_JSON_PACK ( #if FIXME_OEC GNUNET_JSON_pack_allow_null ( @@ -465,9 +616,9 @@ TALER_EXCHANGE_purse_create_with_deposit ( TALER_JSON_pack_denom_sig ("ub_sig", &deposit->denom_sig), GNUNET_JSON_pack_data_auto ("coin_sig", - &coin_sig), + &d->coin_sig), GNUNET_JSON_pack_data_auto ("coin_pub", - &coin_pub)); + &d->coin_pub)); GNUNET_assert (0 == json_array_append_new (deposit_arr, jdeposit)); @@ -529,6 +680,7 @@ TALER_EXCHANGE_purse_create_with_deposit ( curl_easy_cleanup (eh); json_decref (create_obj); GNUNET_free (pch->econtract.econtract); + GNUNET_free (pch->deposits); GNUNET_free (pch->url); GNUNET_free (pch); return NULL; @@ -558,6 +710,7 @@ TALER_EXCHANGE_purse_create_with_deposit_cancel ( } GNUNET_free (pch->econtract.econtract); GNUNET_free (pch->url); + GNUNET_free (pch->deposits); TALER_curl_easy_post_finished (&pch->ctx); GNUNET_free (pch); } |