diff options
| author | Christian Grothoff <christian@grothoff.org> | 2016-05-06 13:33:20 +0200 | 
|---|---|---|
| committer | Christian Grothoff <christian@grothoff.org> | 2016-05-06 13:33:20 +0200 | 
| commit | 302070b86e8c8130f66dc00573af96005c48f7f4 (patch) | |
| tree | 0cbc2a7cd015c271d4e55e32f8c1911f46aecd97 | |
| parent | fbbc49bdada7195f525d5cdff03c68825eabc9a0 (diff) | |
support REFUNDS in transaction history in libtalerexchange
| -rw-r--r-- | src/exchange-lib/exchange_api_common.c | 131 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_responses.c | 54 | 
2 files changed, 165 insertions, 20 deletions
| diff --git a/src/exchange-lib/exchange_api_common.c b/src/exchange-lib/exchange_api_common.c index 15c73acc..6831984f 100644 --- a/src/exchange-lib/exchange_api_common.c +++ b/src/exchange-lib/exchange_api_common.c @@ -40,10 +40,12 @@ int  TALER_EXCHANGE_verify_coin_history (const char *currency,                                       const struct TALER_CoinSpendPublicKeyP *coin_pub,                                       json_t *history, -                                     struct TALER_Amount *total) +                                    struct TALER_Amount *total)  {    size_t len;    size_t off; +  int add; +  struct TALER_Amount rtotal;    if (NULL == history)    { @@ -58,6 +60,8 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,    }    TALER_amount_get_zero (currency,                           total); +  TALER_amount_get_zero (currency, +                         &rtotal);    for (off=0;off<len;off++)    {      json_t *transaction; @@ -89,6 +93,7 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,        GNUNET_break_op (0);        return GNUNET_SYSERR;      } +    add = GNUNET_SYSERR;      if (0 == strcasecmp (type,                           "DEPOSIT"))      { @@ -123,11 +128,12 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,                           &dr->amount_with_fee);        if (0 != TALER_amount_cmp (&dr_amount,                                   &amount)) -        { -          GNUNET_break (0); -          GNUNET_JSON_parse_free (spec); -          return GNUNET_SYSERR; -        } +      { +        GNUNET_break (0); +        GNUNET_JSON_parse_free (spec); +        return GNUNET_SYSERR; +      } +      add = GNUNET_YES;      }      else if (0 == strcasecmp (type,                                "MELT")) @@ -167,6 +173,67 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,          GNUNET_JSON_parse_free (spec);          return GNUNET_SYSERR;        } +      add = GNUNET_YES; +    } +    else if (0 == strcasecmp (type, +                              "REFUND")) +    { +      const struct TALER_RefundRequestPS *rr; +      struct TALER_Amount rr_amount; +      struct TALER_Amount rr_fee; +      struct TALER_Amount rr_delta; + +      if (details_size != sizeof (struct TALER_RefundRequestPS)) +      { +        GNUNET_break_op (0); +        GNUNET_JSON_parse_free (spec); +        return GNUNET_SYSERR; +      } +      rr = (const struct TALER_RefundRequestPS *) details; +      if (details_size != ntohl (rr->purpose.size)) +      { +        GNUNET_break_op (0); +        GNUNET_JSON_parse_free (spec); +        return GNUNET_SYSERR; +      } +      if (GNUNET_OK != +          GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND, +                                      &rr->purpose, +                                      &sig.eddsa_signature, +                                      &rr->merchant.eddsa_pub)) +      { +        GNUNET_break_op (0); +        GNUNET_JSON_parse_free (spec); +        return GNUNET_SYSERR; +      } +      TALER_amount_ntoh (&rr_amount, +                         &rr->refund_amount); +      TALER_amount_ntoh (&rr_fee, +                         &rr->refund_fee); +      if (GNUNET_OK != +          TALER_amount_subtract (&rr_delta, +                                 &rr_amount, +                                 &rr_fee)) +      { +        GNUNET_break_op (0); +        GNUNET_JSON_parse_free (spec); +        return GNUNET_SYSERR; +      } +      if (0 != TALER_amount_cmp (&rr_delta, +                                 &amount)) +      { +        GNUNET_break_op (0); +        GNUNET_JSON_parse_free (spec); +        return GNUNET_SYSERR; +      } +      /* NOTE/FIXME: theoretically, we could also check that the given +         transaction_id and merchant_pub and h_contract appear in the +         history under deposits.  However, there is really no benefit +         for the exchange to lie here, so not checking is probably OK +         (an auditor ought to check, though). Then again, we similarly +         had no reason to check the merchant's signature (other than a +         well-formendess check). */ +      add = GNUNET_NO;      }      else      { @@ -175,18 +242,54 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,        GNUNET_JSON_parse_free (spec);        return GNUNET_SYSERR;      } -    if (GNUNET_OK != -        TALER_amount_add (total, -                          total, -                          &amount)) +    if (GNUNET_YES == add)      { -      /* overflow in history already!? inconceivable! Bad exchange! */ -      GNUNET_break_op (0); -      GNUNET_JSON_parse_free (spec); -      return GNUNET_SYSERR; +      /* This amount should be added to the total */ +      if (GNUNET_OK != +          TALER_amount_add (total, +                            total, +                            &amount)) +      { +        /* overflow in history already!? inconceivable! Bad exchange! */ +        GNUNET_break_op (0); +        GNUNET_JSON_parse_free (spec); +        return GNUNET_SYSERR; +      } +    } +    else +    { +      /* This amount should be subtracted from the total. + +         However, for the implementation, we first *add* up all of +         these negative amounts, as we might get refunds before +         deposits from a semi-evil exchange.  Then, at the end, we do +         the subtraction by calculating "total = total - rtotal" */ +      GNUNET_assert (GNUNET_NO == add); +      if (GNUNET_OK != +          TALER_amount_add (&rtotal, +                            &rtotal, +                            &amount)) +      { +        /* overflow in refund history? inconceivable! Bad exchange! */ +        GNUNET_break_op (0); +        GNUNET_JSON_parse_free (spec); +        return GNUNET_SYSERR; +      }      }      GNUNET_JSON_parse_free (spec);    } + +  /* Finally, subtract 'rtotal' from total to handle the subtractions */ +  if (GNUNET_OK != +      TALER_amount_subtract (total, +                             total, +                             &rtotal)) +  { +    /* underflow in history? inconceivable! Bad exchange! */ +    GNUNET_break_op (0); +    return GNUNET_SYSERR; +  } +    return GNUNET_OK;  } diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c index 2011a5e4..6a21d8ac 100644 --- a/src/exchange/taler-exchange-httpd_responses.c +++ b/src/exchange/taler-exchange-httpd_responses.c @@ -408,7 +408,7 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)    const char *type;    struct TALER_Amount value;    json_t *history; -  const struct TALER_CoinSpendSignatureP *sig; +  const struct GNUNET_CRYPTO_EddsaSignature *sig;    const struct TALER_EXCHANGEDB_TransactionList *pos;    history = json_array (); @@ -436,12 +436,12 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)                             &deposit->deposit_fee);          dr.merchant = deposit->merchant_pub;          dr.coin_pub = deposit->coin.coin_pub; -        sig = &deposit->csig; +        sig = &deposit->csig.eddsa_signature;  	/* internal sanity check before we hand out a bogus sig... */          if (GNUNET_OK !=              GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,                                          &dr.purpose, -                                        &sig->eddsa_signature, +                                        sig,                                          &deposit->coin.coin_pub.eddsa_pub))  	{  	  GNUNET_break (0); @@ -468,12 +468,12 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)          TALER_amount_hton (&ms.melt_fee,                             &melt->melt_fee);          ms.coin_pub = melt->coin.coin_pub; -        sig = &melt->coin_sig; +        sig = &melt->coin_sig.eddsa_signature;  	/* internal sanity check before we hand out a bogus sig... */          if (GNUNET_OK !=              GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,                                          &ms.purpose, -                                        &sig->eddsa_signature, +                                        sig,                                          &melt->coin.coin_pub.eddsa_pub))  	{  	  GNUNET_break (0); @@ -485,6 +485,48 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)                                          sizeof (struct TALER_RefreshMeltCoinAffirmationPS));        }        break; +    case TALER_EXCHANGEDB_TT_REFUND: +      { +        struct TALER_RefundRequestPS rr; +        const struct TALER_EXCHANGEDB_Refund *refund = pos->details.refund; + +        type = "REFUND"; +        if (GNUNET_OK != +            TALER_amount_subtract (&value, +                                   &refund->refund_amount, +                                   &refund->refund_fee)) +        { +	  GNUNET_break (0); +	  json_decref (history); +	  return NULL; +        } +        rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND); +        rr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS)); +        rr.h_contract = refund->h_contract; +        rr.transaction_id = GNUNET_htonll (refund->transaction_id); +        rr.coin_pub = refund->coin.coin_pub; +        rr.merchant = refund->merchant_pub; +        rr.rtransaction_id = GNUNET_htonll (refund->rtransaction_id); +        TALER_amount_hton (&rr.refund_amount, +                           &refund->refund_amount); +        TALER_amount_hton (&rr.refund_fee, +                           &refund->refund_fee); +	/* internal sanity check before we hand out a bogus sig... */ +        if (GNUNET_OK != +            GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND, +                                        &rr.purpose, +                                        sig, +                                        &refund->merchant_pub.eddsa_pub)) +	{ +	  GNUNET_break (0); +	  json_decref (history); +	  return NULL; +	} +        sig = &refund->merchant_sig.eddsa_sig; +        details = GNUNET_JSON_from_data (&rr.purpose, +                                         sizeof (struct TALER_RefundRequestPS)); +      } +      break;      default:        GNUNET_assert (0);      } @@ -493,7 +535,7 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)                                        "type", type,                                        "amount", TALER_JSON_from_amount (&value),                                        "signature", GNUNET_JSON_from_data (sig, -                                                                         sizeof (struct TALER_CoinSpendSignatureP)), +                                                                          sizeof (struct GNUNET_CRYPTO_EddsaSignature)),                                        "details", details));    }    return history; | 
