gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-exchange] branch master updated: work on purse creation logic


From: gnunet
Subject: [taler-exchange] branch master updated: work on purse creation logic
Date: Fri, 01 Apr 2022 16:39:14 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new caf66486 work on purse creation logic
caf66486 is described below

commit caf66486e70d896b1dd4eca3785fd42185a540cd
Author: Christian Grothoff <grothoff@gnunet.org>
AuthorDate: Fri Apr 1 16:39:07 2022 +0200

    work on purse creation logic
---
 contrib/gana                                      |   2 +-
 src/exchange/taler-exchange-httpd_deposit.c       |  12 +-
 src/exchange/taler-exchange-httpd_melt.c          |   2 -
 src/exchange/taler-exchange-httpd_purses_create.c | 249 ++++++++++++++++++----
 src/exchange/taler-exchange-httpd_withdraw.c      |   1 -
 src/exchangedb/plugin_exchangedb_postgres.c       |  23 +-
 src/include/taler_crypto_lib.h                    |  27 +++
 src/include/taler_exchangedb_plugin.h             |  23 +-
 src/include/taler_signatures.h                    |   5 +
 src/util/exchange_signatures.c                    | 113 ++++++++++
 10 files changed, 399 insertions(+), 58 deletions(-)

diff --git a/contrib/gana b/contrib/gana
index 25eb78f2..b799c63d 160000
--- a/contrib/gana
+++ b/contrib/gana
@@ -1 +1 @@
-Subproject commit 25eb78f2d0e20a137020dd0ab1c6474123843dbe
+Subproject commit b799c63db9beda99e9151e7611a1ac4e810786ab
diff --git a/src/exchange/taler-exchange-httpd_deposit.c 
b/src/exchange/taler-exchange-httpd_deposit.c
index 59d25904..011f5f15 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -178,7 +178,6 @@ deposit_transaction (void *cls,
   }
   if (in_conflict)
   {
-    TEH_plugin->rollback (TEH_plugin->cls);
     *mhd_ret
       = TEH_RESPONSE_reply_coin_insufficient_funds (
           connection,
@@ -188,7 +187,6 @@ deposit_transaction (void *cls,
   }
   if (! balance_ok)
   {
-    TEH_plugin->rollback (TEH_plugin->cls);
     *mhd_ret
       = TEH_RESPONSE_reply_coin_insufficient_funds (
           connection,
@@ -323,6 +321,16 @@ TEH_handler_deposit (struct MHD_Connection *connection,
       GNUNET_JSON_parse_free (spec);
       return mret;
     }
+    if (0 > TALER_amount_cmp (&dk->meta.value,
+                              &deposit.amount_with_fee))
+    {
+      GNUNET_break_op (0);
+      GNUNET_JSON_parse_free (spec);
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_BAD_REQUEST,
+                                         
TALER_EC_EXCHANGE_GENERIC_AMOUNT_EXCEEDS_DENOMINATION_VALUE,
+                                         NULL);
+    }
     if (GNUNET_TIME_absolute_is_past (dk->meta.expire_deposit.abs_time))
     {
       /* This denomination is past the expiration time for deposits */
diff --git a/src/exchange/taler-exchange-httpd_melt.c 
b/src/exchange/taler-exchange-httpd_melt.c
index 6fe97c8f..2ff03023 100644
--- a/src/exchange/taler-exchange-httpd_melt.c
+++ b/src/exchange/taler-exchange-httpd_melt.c
@@ -183,7 +183,6 @@ melt_transaction (void *cls,
   if (rmc->zombie_required)
   {
     GNUNET_break_op (0);
-    TEH_plugin->rollback (TEH_plugin->cls);
     *mhd_ret = TALER_MHD_reply_with_error (connection,
                                            MHD_HTTP_BAD_REQUEST,
                                            
TALER_EC_EXCHANGE_MELT_COIN_EXPIRED_NO_ZOMBIE,
@@ -193,7 +192,6 @@ melt_transaction (void *cls,
   if (! balance_ok)
   {
     GNUNET_break_op (0);
-    TEH_plugin->rollback (TEH_plugin->cls);
     *mhd_ret
       = TEH_RESPONSE_reply_coin_insufficient_funds (
           connection,
diff --git a/src/exchange/taler-exchange-httpd_purses_create.c 
b/src/exchange/taler-exchange-httpd_purses_create.c
index ee822b25..75cb448a 100644
--- a/src/exchange/taler-exchange-httpd_purses_create.c
+++ b/src/exchange/taler-exchange-httpd_purses_create.c
@@ -58,6 +58,11 @@ struct Coin
    * Deposit fee applicable for this coin.
    */
   struct TALER_Amount deposit_fee;
+
+  /**
+   * Amount to be put into the purse from this coin.
+   */
+  struct TALER_Amount amount_minus_fee;
 };
 
 
@@ -147,22 +152,22 @@ reply_create_success (struct MHD_Connection *connection,
 {
   struct TALER_ExchangePublicKeyP pub;
   struct TALER_ExchangeSignatureP sig;
-  // FIXME: define what exactly we sign over!
-  struct TALER_DepositConfirmationPS dc = {
-    .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION),
-    .purpose.size = htonl (sizeof (dc)),
-    .h_contract_terms = pcc->h_contract_terms,
-    .purse_pub = *pcc->purse_pub
-  };
   enum TALER_ErrorCode ec;
 
-  TALER_amount_hton (&dc.amount_without_fee,
-                     &pcc->amount);
   if (TALER_EC_NONE !=
-      (ec = TEH_keys_exchange_sign (&dc,
-                                    &pub,
-                                    &sig)))
+      (ec = TALER_exchange_online_purse_created_sign (
+         &TEH_keys_exchange_sign_,
+         pcc->exchange_timestamp,
+         pcc->purse_expiration,
+         &pcc->amount,
+         &pcc->total_deposited,
+         pcc->purse_pub,
+         &pcc->merge_pub,
+         &pcc->h_contract_terms,
+         &pub,
+         &sig)))
   {
+    GNUNET_break (0);
     return TALER_MHD_reply_with_ec (connection,
                                     ec,
                                     NULL);
@@ -170,8 +175,10 @@ reply_create_success (struct MHD_Connection *connection,
   return TALER_MHD_REPLY_JSON_PACK (
     connection,
     MHD_HTTP_OK,
-    // GNUNET_JSON_pack_timestamp ("exchange_timestamp",
-    // pcc->exchange_timestamp),
+    GNUNET_JSON_pack_amount ("total_deposited",
+                             &pcc->deposit_total),
+    GNUNET_JSON_pack_timestamp ("exchange_timestamp",
+                                pcc->exchange_timestamp),
     GNUNET_JSON_pack_data_auto ("exchange_sig",
                                 &sig),
     GNUNET_JSON_pack_data_auto ("exchange_pub",
@@ -199,43 +206,143 @@ create_transaction (void *cls,
 {
   struct PurseCreateContext *pcc = cls;
   enum GNUNET_DB_QueryStatus qs;
-  bool balance_ok;
-  bool in_conflict;
-
-  // 1) create purse
-  // 2) deposit all coins
-  // 3) if present, persist contract
-  // Also: nicely report errors...
-  qs = TEH_plugin->XXX (TEH_plugin->cls, ...);
+  bool in_conflict = true;
+
+  /* 1) create purse */
+  qs = TEH_plugin->insert_purse_request (TEH_plugin->cls,
+                                         &pcc->purse_pub,
+                                         &pcc->merge_pub,
+                                         pcc->purse_expiration,
+                                         &pcc->h_contract_terms,
+                                         pcc->min_age,
+                                         &pcc->amount,
+                                         &pcc->purse_sig,
+                                         &in_conflict);
   if (qs < 0)
   {
     if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
       return qs;
-    TALER_LOG_WARNING ("Failed to store purse information in database\n");
-    *mhd_ret = TALER_MHD_reply_with_error (connection,
-                                           MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                           TALER_EC_GENERIC_DB_STORE_FAILED,
-                                           "purse create");
+    TALER_LOG_WARNING (
+      "Failed to store create purse information in database\n");
+    *mhd_ret =
+      TALER_MHD_reply_with_error (connection,
+                                  MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                  TALER_EC_GENERIC_DB_STORE_FAILED,
+                                  "purse create");
     return qs;
   }
   if (in_conflict)
   {
+    struct TALER_PurseMergePublicKeyP merge_pub;
+    struct GNUNET_TIME_Timestamp purse_expiration;
+    struct TALER_PrivateContractHashP h_contract_terms;
+    struct TALER_Amount target_amount;
+    struct TALER_Amount balance;
+    struct TALER_PurseContractSignatureP purse_sig;
+
     TEH_plugin->rollback (TEH_plugin->cls);
+    qs = TEH_plugin->select_purse_request (TEH_plugin->cls,
+                                           pcc->purse_pub,
+                                           &merge_pub,
+                                           &purse_expiration,
+                                           &h_contract_terms,
+                                           &target_amount,
+                                           &balance,
+                                           &purse_sig);
+    if (qs < 0)
+    {
+      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+      TALER_LOG_WARNING ("Failed to fetch purse information from database\n");
+      *mhd_ret = TALER_MHD_reply_with_error (connection,
+                                             MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                             TALER_EC_GENERIC_DB_FETCH_FAILED,
+                                             "select purse request");
+      return GNUNET_DB_STATUS_HARD_ERROR;
+    }
     *mhd_ret
-      = TEH_RESPONSE_reply_coin_insufficient_funds (
+      =   return TALER_MHD_REPLY_JSON_PACK (
           connection,
-          TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_CONTRACT,
-          &coin->pci.coin_pub);
+          MHD_HTTP_CONFLICT,
+          TALER_JSON_pack_ec (
+            TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_META_DATA),
+          GNUNET_JSON_pack_amount ("amount",
+                                   &amount),
+          GNUNET_JSON_pack_timestamp ("purse_expiration",
+                                      purse_expiration),
+          GNUNET_JSON_pack_data_auto ("purse_sig",
+                                      &purse_sig),
+          GNUNET_JSON_pack_data_auto ("h_contract_terms",
+                                      &h_contract_terms),
+          GNUNET_JSON_pack_data_auto ("merge_pub",
+                                      &merge_pub));
     return GNUNET_DB_STATUS_HARD_ERROR;
   }
-  if (! balance_ok)
+  /* 2) deposit all coins */
+  for (unsigned int i = 0; i<pcc->num_coins; i++)
   {
-    TEH_plugin->rollback (TEH_plugin->cls);
+    struct Coin *coin = &pcc->coins[i];
+    bool balance_ok = false;
+
+    qs = TEH_plugin->do_purse_deposit (TEH_plugin->cls,
+                                       &pcc->purse_pub,
+                                       &coin->cpi.coin_pub,
+                                       &coin->amount,
+                                       &coin->coin_sig,
+                                       &coin->amount_minus_fee,
+                                       &balance_ok);
+    if (qs < 0)
+    {
+      if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+        return qs;
+      TALER_LOG_WARNING (
+        "Failed to store purse deposit information in database\n");
+      *mhd_ret = TALER_MHD_reply_with_error (connection,
+                                             MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                             TALER_EC_GENERIC_DB_STORE_FAILED,
+                                             "purse create deposit");
+      return qs;
+    }
+    if (! balance_ok)
+    {
+      *mhd_ret
+        = TEH_RESPONSE_reply_coin_insufficient_funds (
+            connection,
+            TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
+            &coin->pci.coin_pub);
+      return GNUNET_DB_STATUS_HARD_ERROR;
+    }
+  }
+  /* 3) if present, persist contract */
+  in_conflict = true;
+  qs = TEH_plugin->insert_contract (TEH_plugin->cls,
+                                    &pcc->purse_pub,
+                                    &pcc->contract_pub,
+                                    pcc->econtract_size,
+                                    pcc->econtract,
+                                    &in_conflict);
+  if (qs < 0)
+  {
+    if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+      return qs;
+    TALER_LOG_WARNING ("Failed to store purse information in database\n");
+    *mhd_ret = TALER_MHD_reply_with_error (connection,
+                                           MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                           TALER_EC_GENERIC_DB_STORE_FAILED,
+                                           "purse create contract");
+    return qs;
+  }
+  if (in_conflict)
+  {
+    /* FIXME-DESIGN: we have no proof that the
+       client is at fault here!
+       => need 2nd client signature over the encrypted
+       contract (and ECDHE public key)!!! */
     *mhd_ret
-      = TEH_RESPONSE_reply_coin_insufficient_funds (
+      = TEH_RESPONSE_reply_with_error (
           connection,
-          TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
-          &coin->pci.coin_pub);
+          MHD_HTTP_INTERNAL_SERVER_ERROR,
+          TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_CONTRACT_STORED,
+          NULL);
     return GNUNET_DB_STATUS_HARD_ERROR;
   }
   return qs;
@@ -289,7 +396,7 @@ parse_coin (struct MHD_Connection *connection,
   }
 
   if (GNUNET_OK !=
-      TALER_wallet_purse_deposit_verify ("http://FIXME-URL";,
+      TALER_wallet_purse_deposit_verify (TEH_base_url,
                                          &pcc->purse_pub,
                                          &pcc->amount,
                                          &coin->coin_pub,
@@ -301,7 +408,7 @@ parse_coin (struct MHD_Connection *connection,
             TALER_MHD_reply_with_error (connection,
                                         MHD_HTTP_UNAUTHORIZED,
                                         
TALER_EC_EXCHANGE_PURSE_CREATE_COIN_SIGNATURE_INVALID,
-                                        NULL))
+                                        TEH_base_url))
            ? GNUNET_NO : GNUNET_SYSERR;
   }
   /* check denomination exists and is valid */
@@ -317,6 +424,18 @@ parse_coin (struct MHD_Connection *connection,
       GNUNET_JSON_parse_free (spec);
       return (MHD_YES == mret) ? GNUNET_NO : GNUNET_SYSERR:
     }
+    if (0 > TALER_amount_cmp (&dk->meta.value,
+                              &coin->amount))
+    {
+      GNUNET_break_op (0);
+      GNUNET_JSON_parse_free (spec);
+      return (MHD_YES ==
+              TALER_MHD_reply_with_error (connection,
+                                          MHD_HTTP_BAD_REQUEST,
+                                          
TALER_EC_EXCHANGE_GENERIC_AMOUNT_EXCEEDS_DENOMINATION_VALUE,
+                                          NULL))
+             ? GNUNET_NO : GNUNET_SYSERR;
+    }
     if (GNUNET_TIME_absolute_is_past (dk->meta.expire_deposit.abs_time))
     {
       /* This denomination is past the expiration time for deposits */
@@ -366,6 +485,20 @@ parse_coin (struct MHD_Connection *connection,
     }
 
     coin->deposit_fee = dk->meta.fees.deposit;
+    if (0 < TALER_amount_cmp (&coin->deposit_fee,
+                              &coin->amount))
+    {
+      GNUNET_break_op (0);
+      GNUNET_JSON_parse_free (spec);
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_BAD_REQUEST,
+                                         
TALER_EC_EXCHANGE_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE,
+                                         NULL);
+    }
+    GNUNET_assert (0 <=
+                   TALER_amount_subtact (&coin->amount_minus_fee,
+                                         &coin->amount,
+                                         &coin->deposit_fee));
     /* check coin signature */
     switch (dk->denom_pub.cipher)
     {
@@ -391,6 +524,17 @@ parse_coin (struct MHD_Connection *connection,
                                           NULL))
              ? GNUNET_NO : GNUNET_SYSERR;
     }
+    if (0 >
+        TALER_amount_add (&pcc->deposit_total,
+                          &pcc->deposit_total,
+                          &coin->amount_minus_fee))
+    {
+      GNUNET_break (0);
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                         
TALER_EC_GENERIC_FAILED_COMPUTE_AMOUNT,
+                                         "total deposit contribution");
+    }
   }
   {
     MHD_RESULT mhd_ret = MHD_NO;
@@ -425,10 +569,10 @@ parse_coin (struct MHD_Connection *connection,
 
 
 MHD_RESULT
-TEH_handler_purses_create (struct MHD_Connection *connection,
-                           const struct
-                           TALER_PurseContractPublicKeyP *purse_pub,
-                           const json_t *root)
+TEH_handler_purses_create (
+  struct MHD_Connection *connection,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const json_t *root)
 {
   struct PurseCreateContext pcc = {
     .purse_pub = purse_pub,
@@ -461,6 +605,7 @@ TEH_handler_purses_create (struct MHD_Connection 
*connection,
                                 &pcc.purse_expiration),
     GNUNET_JSON_spec_end ()
   };
+  const struct TEH_GlobalFee *gf;
 
   {
     enum GNUNET_GenericReturnValue res;
@@ -479,7 +624,9 @@ TEH_handler_purses_create (struct MHD_Connection 
*connection,
       return MHD_YES; /* failure */
     }
   }
-
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_amount_set_zero (TEH_currency,
+                                        &pcc.deposit_total));
   if (GNUNET_TIME_timestamp_cmp (pcc.purse_expiration,
                                  <,
                                  pcc.exchange_timestamp))
@@ -511,6 +658,17 @@ TEH_handler_purses_create (struct MHD_Connection 
*connection,
                                        
TALER_EC_EXCHANGE_GENERIC_PARAMETER_MALFORMED,
                                        "deposits");
   }
+  gf = TEH_keys_global_fee_by_time (TEH_keys_get_state (),
+                                    pcc.exchange_timestamp);
+  if (NULL == gf)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Cannot create purse: global fees not configured!\n");
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                       
TALER_EC_EXCHANGE_GENERIC_GLOBAL_FEES_MISSING,
+                                       NULL);
+  }
   /* parse deposits */
   pcc.coins = GNUNET_new_array (struct Coin,
                                 pcc.num_coins);
@@ -531,8 +689,7 @@ TEH_handler_purses_create (struct MHD_Connection 
*connection,
     }
   }
 
-  // FIXME: get purse_fee!
-  if (0 < TALER_amount_cmp (&purse_fee,
+  if (0 < TALER_amount_cmp (&gf->fees.purse,
                             &pcc.deposit_total))
   {
     GNUNET_break_op (0);
@@ -543,7 +700,6 @@ TEH_handler_purses_create (struct MHD_Connection 
*connection,
                                        
TALER_EC_EXCHANGE_CREATE_PURSE_NEGATIVE_VALUE_AFTER_FEE,
                                        NULL);
   }
-
   TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
 
   if (GNUNET_OK !=
@@ -560,7 +716,7 @@ TEH_handler_purses_create (struct MHD_Connection 
*connection,
     GNUNET_free (pcc.coins);
     return TALER_MHD_reply_with_error (connection,
                                        MHD_HTTP_UNAUTHORIZED,
-                                       
TALER_EC_EXCHANGE_PURSE_CREATE_COIN_SIGNATURE_INVALID,
+                                       
TALER_EC_EXCHANGE_PURSE_CREATE_SIGNATURE_INVALID,
                                        NULL);
   }
 
@@ -568,6 +724,7 @@ TEH_handler_purses_create (struct MHD_Connection 
*connection,
       TEH_plugin->preflight (TEH_plugin->cls))
   {
     GNUNET_break (0);
+    GNUNET_JSON_parse_free (spec);
     GNUNET_free (pcc.coins);
     return TALER_MHD_reply_with_error (connection,
                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
diff --git a/src/exchange/taler-exchange-httpd_withdraw.c 
b/src/exchange/taler-exchange-httpd_withdraw.c
index 5765181b..d5ecd338 100644
--- a/src/exchange/taler-exchange-httpd_withdraw.c
+++ b/src/exchange/taler-exchange-httpd_withdraw.c
@@ -256,7 +256,6 @@ withdraw_transaction (void *cls,
     }
     if (! below_limit)
     {
-      TEH_plugin->rollback (TEH_plugin->cls);
       *mhd_ret = TALER_MHD_REPLY_JSON_PACK (
         connection,
         MHD_HTTP_ACCEPTED,
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c 
b/src/exchangedb/plugin_exchangedb_postgres.c
index ec26a6dd..8f0f5e22 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -12668,6 +12668,10 @@ postgres_insert_partner (void *cls,
  * @param pub_ckey ephemeral key for DH used to encrypt the contract
  * @param econtract_size number of bytes in @a econtract
  * @param econtract the encrypted contract
+ * @param[out] in_conflict set to true if @a econtract
+ *             conflicts with an existing contract;
+ *             in this case, the return value will be
+ *             #GNUNET_DB_STATUS_SUCCESS_ONE despite the failure
  * @return transaction status code
  */
 static enum GNUNET_DB_QueryStatus
@@ -12675,7 +12679,8 @@ postgres_insert_contract (void *cls,
                           const struct TALER_PurseContractPublicKeyP 
*purse_pub,
                           const struct TALER_ContractDiffiePublicP *pub_ckey,
                           size_t econtract_size,
-                          const void *econtract)
+                          const void *econtract,
+                          bool *in_conflict)
 {
   GNUNET_break (0);
   return GNUNET_DB_STATUS_HARD_ERROR;
@@ -12715,6 +12720,10 @@ postgres_select_contract (void *cls,
  * @param age_limit age limit to enforce for payments into the purse
  * @param amount target amount (with fees) to be put into the purse
  * @param purse_sig signature with @a purse_pub's private key affirming the 
above
+ * @param[out] in_conflict set to true if the meta data
+ *             conflicts with an existing purse;
+ *             in this case, the return value will be
+ *             #GNUNET_DB_STATUS_SUCCESS_ONE despite the failure
  * @return transaction status code
  */
 static enum GNUNET_DB_QueryStatus
@@ -12726,7 +12735,8 @@ postgres_insert_purse_request (
   const struct TALER_PrivateContractHashP *h_contract_terms,
   uint32_t age_limit,
   const struct TALER_Amount *amount,
-  const struct TALER_PurseContractSignatureP *purse_sig)
+  const struct TALER_PurseContractSignatureP *purse_sig,
+  bool *in_conflict)
 {
   GNUNET_break (0);
   return GNUNET_DB_STATUS_HARD_ERROR;
@@ -12806,6 +12816,11 @@ postgres_select_purse_by_merge_pub (
  * @param coin_pub coin to deposit (debit)
  * @param amount fraction of the coin's value to deposit
  * @param coin_sig signature affirming the operation
+ * @param amount_minus_fee amount to add to the purse
+ * @param[out] balance_ok set to false if the coin's
+ *        remaining balance is below @a amount;
+ *             in this case, the return value will be
+ *             #GNUNET_DB_STATUS_SUCCESS_ONE despite the failure
  * @return transaction status code
  */
 static enum GNUNET_DB_QueryStatus
@@ -12814,7 +12829,9 @@ postgres_do_purse_deposit (
   const struct TALER_PurseContractPublicKeyP *purse_pub,
   const struct TALER_CoinSpendPublicKeyP *coin_pub,
   const struct TALER_Amount *amount,
-  const struct TALER_CoinSpendSignatureP *coin_sig)
+  const struct TALER_CoinSpendSignatureP *coin_sig,
+  const struct TALER_Amount *amount_minus_fee,
+  bool *balance_ok)
 {
   GNUNET_break (0);
   return GNUNET_DB_STATUS_HARD_ERROR;
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index bafcca08..6b554dfb 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -3811,6 +3811,33 @@ TALER_exchange_online_reserve_closed_verify (
   const struct TALER_ExchangeSignatureP *sig);
 
 
+enum TALER_ErrorCode
+TALER_exchange_online_purse_created_sign (
+  TALER_ExchangeSignCallback scb,
+  struct GNUNET_TIME_Timestamp exchange_time,
+  struct GNUNET_TIME_Timestamp purse_expiration,
+  const struct TALER_Amount *amount_without_fee,
+  const struct TALER_Amount *total_deposited,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const struct TALER_PurseMergePublicKeyP *merge_pub,
+  const struct TALER_PrivateContractHashP *h_contract_terms,
+  struct TALER_ExchangePublicKeyP *pub,
+  struct TALER_ExchangeSignatureP *sig);
+
+
+enum GNUNET_GenericReturnValue
+TALER_exchange_online_purse_created_verify (
+  struct GNUNET_TIME_Timestamp exchange_time,
+  struct GNUNET_TIME_Timestamp purse_expiration,
+  const struct TALER_Amount *amount_without_fee,
+  const struct TALER_Amount *total_deposited,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const struct TALER_PurseMergePublicKeyP *merge_pub,
+  const struct TALER_PrivateContractHashP *h_contract_terms,
+  const struct TALER_ExchangePublicKeyP *pub,
+  const struct TALER_ExchangeSignatureP *sig);
+
+
 /* ********************* offline signing ************************** */
 
 
diff --git a/src/include/taler_exchangedb_plugin.h 
b/src/include/taler_exchangedb_plugin.h
index 6b86dc3c..488ffd51 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -4389,6 +4389,10 @@ struct TALER_EXCHANGEDB_Plugin
    * @param pub_ckey ephemeral key for DH used to encrypt the contract
    * @param econtract_size number of bytes in @a econtract
    * @param econtract the encrypted contract
+   * @param[out] in_conflict set to true if @a econtract
+   *             conflicts with an existing contract;
+   *             in this case, the return value will be
+   *             #GNUNET_DB_STATUS_SUCCESS_ONE despite the failure
    * @return transaction status code
    */
   enum GNUNET_DB_QueryStatus
@@ -4396,7 +4400,8 @@ struct TALER_EXCHANGEDB_Plugin
                      const struct TALER_PurseContractPublicKeyP *purse_pub,
                      const struct TALER_ContractDiffiePublicP *pub_ckey,
                      size_t econtract_size,
-                     const void *econtract);
+                     const void *econtract,
+                     bool *in_conflict);
 
 
   /**
@@ -4428,6 +4433,10 @@ struct TALER_EXCHANGEDB_Plugin
    * @param age_limit age limit to enforce for payments into the purse
    * @param amount target amount (with fees) to be put into the purse
    * @param purse_sig signature with @a purse_pub's private key affirming the 
above
+   * @param[out] in_conflict set to true if the meta data
+   *             conflicts with an existing purse;
+   *             in this case, the return value will be
+   *             #GNUNET_DB_STATUS_SUCCESS_ONE despite the failure
    * @return transaction status code
    */
   enum GNUNET_DB_QueryStatus
@@ -4439,7 +4448,8 @@ struct TALER_EXCHANGEDB_Plugin
     const struct TALER_PrivateContractHashP *h_contract_terms,
     uint32_t age_limit,
     const struct TALER_Amount *amount,
-    const struct TALER_PurseContractSignatureP *purse_sig);
+    const struct TALER_PurseContractSignatureP *purse_sig,
+    bool *in_conflict);
 
 
   /**
@@ -4507,6 +4517,11 @@ struct TALER_EXCHANGEDB_Plugin
    * @param coin_pub coin to deposit (debit)
    * @param amount fraction of the coin's value to deposit
    * @param coin_sig signature affirming the operation
+   * @param amount_minus_fee amount to add to the purse
+   * @param[out] balance_ok set to false if the coin's
+   *        remaining balance is below @a amount;
+   *             in this case, the return value will be
+   *             #GNUNET_DB_STATUS_SUCCESS_ONE despite the failure
    * @return transaction status code
    */
   enum GNUNET_DB_QueryStatus
@@ -4515,7 +4530,9 @@ struct TALER_EXCHANGEDB_Plugin
     const struct TALER_PurseContractPublicKeyP *purse_pub,
     const struct TALER_CoinSpendPublicKeyP *coin_pub,
     const struct TALER_Amount *amount,
-    const struct TALER_CoinSpendSignatureP *coin_sig);
+    const struct TALER_CoinSpendSignatureP *coin_sig,
+    const struct TALER_Amount *amount_minus_fee,
+    bool *balance_ok);
 
 
   /**
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index 52c294ce..70c917b6 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -176,6 +176,11 @@
  */
 #define TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS 1044
 
+/**
+ * Signature by which the exchange affirms that a purse
+ * was created with a certain amount deposited into it.
+ */
+#define TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION 1045
 
 /**********************/
 /* Auditor signatures */
diff --git a/src/util/exchange_signatures.c b/src/util/exchange_signatures.c
index 4bfa822f..eeec0d61 100644
--- a/src/util/exchange_signatures.c
+++ b/src/util/exchange_signatures.c
@@ -1261,4 +1261,117 @@ TALER_exchange_online_reserve_closed_verify (
 }
 
 
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Response by which the exchange affirms that it has
+ * received funds deposited into a purse.
+ */
+struct TALER_PurseCreateDepositConfirmationPS
+{
+
+  /**
+   * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION
+   */
+  struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+  /**
+   * When did the exchange receive the deposits.
+   */
+  struct GNUNET_TIME_TimestampNBO exchange_time;
+
+  /**
+   * When will the purse expire?
+   */
+  struct GNUNET_TIME_TimestampNBO purse_expiration;
+
+  /**
+   * How much should the purse ultimately contain.
+   */
+  struct TALER_AmountNBO amount_without_fee;
+
+  /**
+   * How much was deposited so far.
+   */
+  struct TALER_AmountNBO total_deposited;
+
+  /**
+   * Public key of the purse.
+   */
+  struct TALER_PurseContractPublicKeyP purse_pub;
+
+  /**
+   * Public key of the merge capability.
+   */
+  struct TALER_PurseMergePublicKeyP merge_pub;
+
+  /**
+   * Hash of the contract of the purse.
+   */
+  struct TALER_PrivateContractHashP h_contract_terms;
+
+};
+
+GNUNET_NETWORK_STRUCT_END
+
+
+enum TALER_ErrorCode
+TALER_exchange_online_purse_created_sign (
+  TALER_ExchangeSignCallback scb,
+  struct GNUNET_TIME_Timestamp exchange_time,
+  struct GNUNET_TIME_Timestamp purse_expiration,
+  const struct TALER_Amount *amount_without_fee,
+  const struct TALER_Amount *total_deposited,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const struct TALER_PurseMergePublicKeyP *merge_pub,
+  const struct TALER_PrivateContractHashP *h_contract_terms,
+  struct TALER_ExchangePublicKeyP *pub,
+  struct TALER_ExchangeSignatureP *sig)
+{
+  struct TALER_PurseCreateDepositConfirmationPS dc = {
+    .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION),
+    .purpose.size = htonl (sizeof (dc)),
+    .h_contract_terms = *h_contract_terms,
+    .purse_pub = *purse_pub,
+    .merge_pub = *merge_pub,
+    .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration),
+    .exchange_time = GNUNET_TIME_timestamp_hton (exchange_time)
+  };
+
+  return scb (&dc.purpose,
+              pub,
+              sig);
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_exchange_online_purse_created_verify (
+  struct GNUNET_TIME_Timestamp exchange_time,
+  struct GNUNET_TIME_Timestamp purse_expiration,
+  const struct TALER_Amount *amount_without_fee,
+  const struct TALER_Amount *total_deposited,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const struct TALER_PurseMergePublicKeyP *merge_pub,
+  const struct TALER_PrivateContractHashP *h_contract_terms,
+  const struct TALER_ExchangePublicKeyP *pub,
+  const struct TALER_ExchangeSignatureP *sig)
+{
+  struct TALER_PurseCreateDepositConfirmationPS dc = {
+    .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION),
+    .purpose.size = htonl (sizeof (dc)),
+    .h_contract_terms = *h_contract_terms,
+    .purse_pub = *purse_pub,
+    .merge_pub = *merge_pub,
+    .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration),
+    .exchange_time = GNUNET_TIME_timestamp_hton (exchange_time)
+  };
+
+  return
+    GNUNET_CRYPTO_eddsa_verify 
(TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION,
+                                &dc,
+                                &sig->eddsa_signature,
+                                &pub->eddsa_pub);
+}
+
+
 /* end of exchange_signatures.c */

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]