diff options
| author | Christian Grothoff <christian@grothoff.org> | 2019-07-21 20:15:11 +0200 | 
|---|---|---|
| committer | Christian Grothoff <christian@grothoff.org> | 2019-07-21 20:15:11 +0200 | 
| commit | 721c1ee73e1ee65ab9a246456ef4acce3e2338f5 (patch) | |
| tree | 0529603b8b6bf2ac3043af3d64e7cd0705f138d9 /src | |
| parent | bafe0c772a7b93934ff2d3797dcd4d9993764d16 (diff) | |
extending postgres plugin with functions required to store payback data on refreshed coins for #5777
Diffstat (limited to 'src')
| -rw-r--r-- | src/exchangedb/plugin_exchangedb_common.c | 6 | ||||
| -rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 725 | ||||
| -rw-r--r-- | src/include/taler_exchangedb_plugin.h | 177 | 
3 files changed, 743 insertions, 165 deletions
diff --git a/src/exchangedb/plugin_exchangedb_common.c b/src/exchangedb/plugin_exchangedb_common.c index fd2620c7..4a72f546 100644 --- a/src/exchangedb/plugin_exchangedb_common.c +++ b/src/exchangedb/plugin_exchangedb_common.c @@ -99,6 +99,9 @@ common_free_coin_transaction_list (void *cls,          GNUNET_CRYPTO_rsa_signature_free (list->details.melt->session.coin.denom_sig.rsa_signature);        GNUNET_free (list->details.melt);        break; +    case TALER_EXCHANGEDB_TT_OLD_COIN_PAYBACK: +      GNUNET_free (list->details.old_coin_payback); +      break;      case TALER_EXCHANGEDB_TT_REFUND:        if (NULL != list->details.refund->coin.denom_sig.rsa_signature)          GNUNET_CRYPTO_rsa_signature_free (list->details.refund->coin.denom_sig.rsa_signature); @@ -109,6 +112,9 @@ common_free_coin_transaction_list (void *cls,          GNUNET_CRYPTO_rsa_signature_free (list->details.payback->coin.denom_sig.rsa_signature);        GNUNET_free (list->details.payback);        break; +    case TALER_EXCHANGEDB_TT_PAYBACK_REFRESH: +      GNUNET_free (list->details.payback_refresh); +      break;      }      GNUNET_free (list);      list = next; diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index b4c2d49d..cbf4c093 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -115,6 +115,7 @@ postgres_drop_tables (void *cls)      GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS kyc_merchants CASCADE;"),      GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS prewire CASCADE;"),      GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS payback CASCADE;"), +    GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS payback_refresh CASCADE;"),      GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS aggregation_tracking CASCADE;"),      GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS wire_out CASCADE;"),      GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS wire_fee CASCADE;"), @@ -317,7 +318,7 @@ postgres_create_tables (void *cls)                             ",newcoin_index INT4 NOT NULL"                             ",link_sig BYTEA NOT NULL CHECK(LENGTH(link_sig)=64)"                             ",denom_pub_hash BYTEA NOT NULL REFERENCES denominations (denom_pub_hash) ON DELETE CASCADE" -                           ",coin_ev BYTEA NOT NULL" +                           ",coin_ev BYTEA UNIQUE NOT NULL"                             ",ev_sig BYTEA NOT NULL"                             ",PRIMARY KEY (rc, newcoin_index)"                             ");"), @@ -449,6 +450,27 @@ postgres_create_tables (void *cls)      GNUNET_PQ_make_try_execute("CREATE INDEX payback_for_by_reserve "                                 "ON payback(coin_pub,denom_pub_hash,h_blind_ev);"), +    /* Table for /payback-refresh information */ +    GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS payback_refresh " +                           "(payback_refresh_uuid BIGSERIAL UNIQUE" +                           ",coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub)" /* do NOT CASCADE on delete, we may keep the coin alive! */ +                           ",coin_sig BYTEA NOT NULL CHECK(LENGTH(coin_sig)=64)" +                           ",coin_blind BYTEA NOT NULL CHECK(LENGTH(coin_blind)=32)" +                           ",amount_val INT8 NOT NULL" +                           ",amount_frac INT4 NOT NULL" +                           ",amount_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" +                           ",timestamp INT8 NOT NULL" +                           ",h_blind_ev BYTEA NOT NULL REFERENCES refresh_revealed_coins (coin_ev) ON DELETE CASCADE" +                           ");"), +    GNUNET_PQ_make_try_execute("CREATE INDEX payback_refresh_by_coin_index " +                               "ON payback_refresh(coin_pub);"), +    GNUNET_PQ_make_try_execute("CREATE INDEX payback_refresh_by_h_blind_ev " +                               "ON payback_refresh(h_blind_ev);"), +    GNUNET_PQ_make_try_execute("CREATE INDEX payback_refresh_by_reserve_index " +                               "ON payback_refresh(reserve_pub);"), +    GNUNET_PQ_make_try_execute("CREATE INDEX payback_refresh_for_by_reserve " +                               "ON payback_refresh(coin_pub,denom_pub_hash,h_blind_ev);"), +      /* This table contains the pre-commit data for         wire transfers the exchange is about to execute. */      GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS prewire " @@ -658,14 +680,14 @@ postgres_prepare (PGconn *db_conn)                              ") VALUES "                              "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);",                              10), -    /* Used in #postgres_reserves_update() when the reserve is updated */ +    /* Used in #reserves_update() when the reserve is updated */      GNUNET_PQ_make_prepare ("reserve_update",                              "UPDATE reserves"                              " SET"                              " expiration_date=$1 "                              ",current_balance_val=$2"                              ",current_balance_frac=$3" -			    ",current_balance_curr=$4" +                            ",current_balance_curr=$4"                              " WHERE"                              " reserve_pub=$5;",                              5), @@ -1521,6 +1543,21 @@ postgres_prepare (PGconn *db_conn)                              ") VALUES "                              "($1, $2, $3, $4, $5, $6, $7, $8);",                              8), +    /* Used in #postgres_insert_payback_request() to store payback-refresh +       information */ +    GNUNET_PQ_make_prepare ("payback_refresh_insert", +                            "INSERT INTO payback_refresh " +                            "(coin_pub" +                            ",coin_sig" +                            ",coin_blind" +                            ",amount_val" +                            ",amount_frac" +                            ",amount_curr" +                            ",timestamp" +                            ",h_blind_ev" +                            ") VALUES " +                            "($1, $2, $3, $4, $5, $6, $7, $8);", +                            8),      /* Used in #postgres_select_payback_above_serial_id() to obtain payback transactions */      GNUNET_PQ_make_prepare ("payback_get_incr",                              "SELECT" @@ -1547,6 +1584,35 @@ postgres_prepare (PGconn *db_conn)                              " WHERE payback_uuid>=$1"                              " ORDER BY payback_uuid ASC;",                              1), +    /* Used in #postgres_select_payback_refresh_above_serial_id() to obtain +       payback-refresh transactions */ +    GNUNET_PQ_make_prepare ("payback_refresh_get_incr", +                            "SELECT" +                            " payback_refresh_uuid" +                            ",timestamp" +                            ",rc.old_coin_pub" +                            ",coin_pub" +                            ",coin_sig" +                            ",coin_blind" +                            ",h_blind_ev" +                            ",coins.denom_pub_hash" +                            ",denoms.denom_pub" +                            ",coins.denom_sig" +                            ",amount_val" +                            ",amount_frac" +                            ",amount_curr" +                            " FROM payback_refresh" +                            "    JOIN refresh_revealed_coins rrc" +                            "      ON (rrc.coin_ev = h_blind_ev)" +                            "    JOIN refresh_commitments rc" +                            "      ON (rrc.rc = rc.rc)" +                            "    JOIN known_coins coins" +                            "      USING (coin_pub)" +                            "    JOIN denominations denoms" +                            "      ON (coins.denom_pub_hash = denoms.denom_pub_hash)" +                            " WHERE payback_refresh_uuid>=$1" +                            " ORDER BY payback_refresh_uuid ASC;", +                            1),      /* Used in #postgres_select_reserve_closed_above_serial_id() to         obtain information about closed reserves */      GNUNET_PQ_make_prepare ("reserves_close_get_incr", @@ -1587,6 +1653,29 @@ postgres_prepare (PGconn *db_conn)                              " WHERE ro.reserve_pub=$1"                              " FOR UPDATE;",                              1), +    /* Used in #postgres_get_coin_transactions() to obtain payback transactions +       affecting old coins of refreshed coins */ +    GNUNET_PQ_make_prepare ("payback_by_old_coin", +                            "SELECT" +                            " pr.coin_pub" +                            ",pr.coin_sig" +                            ",pr.coin_blind" +                            ",pr.amount_val" +                            ",pr.amount_frac" +                            ",pr.amount_curr" +                            ",pr.timestamp" +                            ",coins.denom_pub_hash" +                            ",coins.denom_sig" +                            " FROM refresh_commitments" +                            "    JOIN refresh_revealed_coins rrc" +                            "      USING (rc)" +                            "    JOIN payback_refresh pr" +                            "      ON (rrc.coin_ev = pr.h_blind_ev)" +                            "    JOIN known_coins coins" +                            "      ON (coins.coin_pub = pr.coin_pub)" +                            " WHERE old_coin_pub=$1" +                            " FOR UPDATE;", +                            1),      /* Used in #postgres_get_reserve_history() */      GNUNET_PQ_make_prepare ("close_by_reserve",                              "SELECT" @@ -1616,8 +1705,8 @@ postgres_prepare (PGconn *db_conn)                              " WHERE expiration_date<=$1"                              "   AND (current_balance_val != 0 "                              "        OR current_balance_frac != 0)" -			    " ORDER BY expiration_date ASC" -			    " LIMIT 1;", +                            " ORDER BY expiration_date ASC" +                            " LIMIT 1;",                              1),      /* Used in #postgres_get_coin_transactions() to obtain payback transactions         for a coin */ @@ -1637,7 +1726,31 @@ postgres_prepare (PGconn *db_conn)                              "      USING (coin_pub)"                              "    JOIN reserves_out ro"                              "      USING (h_blind_ev)" -                            " WHERE payback.coin_pub=$1;", +                            " WHERE payback.coin_pub=$1" +                            " FOR UPDATE;", +                            1), +    /* Used in #postgres_get_coin_transactions() to obtain payback transactions +       for a refreshed coin */ +    GNUNET_PQ_make_prepare ("payback_by_refreshed_coin", +                            "SELECT" +                            " rc.old_coin_pub" +                            ",coin_sig" +                            ",coin_blind" +                            ",amount_val" +                            ",amount_frac" +                            ",amount_curr" +                            ",timestamp" +                            ",coins.denom_pub_hash" +                            ",coins.denom_sig" +                            " FROM payback_refresh" +                            "    JOIN refresh_revealed_coins rrc" +                            "      ON (rrc.coin_ev = h_blind_ev)" +                            "    JOIN refresh_commitments rc" +                            "      ON (rrc.rc = rc.rc)" +                            "    JOIN known_coins coins" +                            "      USING (coin_pub)" +                            " WHERE coin_pub=$1" +                            " FOR UPDATE;",                              1),      /* Used in #postgres_get_reserve_by_h_blind() */      GNUNET_PQ_make_prepare ("reserve_by_h_blind", @@ -2181,8 +2294,8 @@ reserves_update (void *cls,    };    return GNUNET_PQ_eval_prepared_non_select (session->conn, -					     "reserve_update", -					     params); +                                             "reserve_update", +                                             params);  } @@ -2334,8 +2447,8 @@ postgres_reserves_in_insert (void *cls,      updated_reserve.expiry = GNUNET_TIME_absolute_max (expiry,                                                         reserve.expiry);      return reserves_update (cls, -			    session, -			    &updated_reserve); +                            session, +                            &updated_reserve);    }    return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;  } @@ -2504,8 +2617,8 @@ postgres_insert_withdraw_info (void *cls,    reserve.expiry = GNUNET_TIME_absolute_max (expiry,                                               reserve.expiry);    qs = reserves_update (cls, -			session, -			&reserve); +                        session, +                        &reserve);    GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);    if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)    { @@ -4253,8 +4366,8 @@ struct CoinHistoryContext   */  static void  add_coin_deposit (void *cls, -		  PGresult *result, -		  unsigned int num_results) +                  PGresult *result, +                  unsigned int num_results)  {    struct CoinHistoryContext *chc = cls; @@ -4267,38 +4380,38 @@ add_coin_deposit (void *cls,      deposit = GNUNET_new (struct TALER_EXCHANGEDB_Deposit);      {        struct GNUNET_PQ_ResultSpec rs[] = { -	TALER_PQ_result_spec_amount ("amount_with_fee", -				     &deposit->amount_with_fee), -	TALER_PQ_result_spec_amount ("fee_deposit", -				     &deposit->deposit_fee), -	TALER_PQ_result_spec_absolute_time ("timestamp", -					     &deposit->timestamp), -	TALER_PQ_result_spec_absolute_time ("refund_deadline", -					     &deposit->refund_deadline), -	TALER_PQ_result_spec_absolute_time ("wire_deadline", -					     &deposit->wire_deadline), -	GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", -					      &deposit->merchant_pub), -	GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms", -					      &deposit->h_contract_terms), -	GNUNET_PQ_result_spec_auto_from_type ("h_wire", -					      &deposit->h_wire), -	TALER_PQ_result_spec_json ("wire", +        TALER_PQ_result_spec_amount ("amount_with_fee", +                                     &deposit->amount_with_fee), +        TALER_PQ_result_spec_amount ("fee_deposit", +                                     &deposit->deposit_fee), +        TALER_PQ_result_spec_absolute_time ("timestamp", +                                            &deposit->timestamp), +        TALER_PQ_result_spec_absolute_time ("refund_deadline", +                                            &deposit->refund_deadline), +        TALER_PQ_result_spec_absolute_time ("wire_deadline", +                                            &deposit->wire_deadline), +        GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", +                                              &deposit->merchant_pub), +        GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms", +                                              &deposit->h_contract_terms), +        GNUNET_PQ_result_spec_auto_from_type ("h_wire", +                                              &deposit->h_wire), +        TALER_PQ_result_spec_json ("wire",                                     &deposit->receiver_wire_account), -	GNUNET_PQ_result_spec_auto_from_type ("coin_sig", -					      &deposit->csig), -	GNUNET_PQ_result_spec_end +        GNUNET_PQ_result_spec_auto_from_type ("coin_sig", +                                              &deposit->csig), +        GNUNET_PQ_result_spec_end        };        if (GNUNET_OK != -	  GNUNET_PQ_extract_result (result, -				    rs, -				    i)) +          GNUNET_PQ_extract_result (result, +                                    rs, +                                    i))        { -	GNUNET_break (0); -	GNUNET_free (deposit); -	chc->status = GNUNET_DB_STATUS_HARD_ERROR; -	return; +        GNUNET_break (0); +        GNUNET_free (deposit); +        chc->status = GNUNET_DB_STATUS_HARD_ERROR; +        return;        }        deposit->coin.coin_pub = *chc->coin_pub;      } @@ -4332,8 +4445,8 @@ add_coin_deposit (void *cls,   */  static void  add_coin_melt (void *cls, -	       PGresult *result, -	       unsigned int num_results) +               PGresult *result, +               unsigned int num_results)  {    struct CoinHistoryContext *chc = cls; @@ -4346,27 +4459,27 @@ add_coin_melt (void *cls,      melt = GNUNET_new (struct TALER_EXCHANGEDB_RefreshMelt);      {        struct GNUNET_PQ_ResultSpec rs[] = { -	GNUNET_PQ_result_spec_auto_from_type ("rc", -					      &melt->session.rc), -	/* oldcoin_index not needed */ -	GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig", -					      &melt->session.coin_sig), -	TALER_PQ_result_spec_amount ("amount_with_fee", -				     &melt->session.amount_with_fee), -	TALER_PQ_result_spec_amount ("fee_refresh", -				     &melt->melt_fee), -	GNUNET_PQ_result_spec_end +  	    GNUNET_PQ_result_spec_auto_from_type ("rc", +                                              &melt->session.rc), +        /* oldcoin_index not needed */ +        GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig", +                                              &melt->session.coin_sig), +        TALER_PQ_result_spec_amount ("amount_with_fee", +                                     &melt->session.amount_with_fee), +        TALER_PQ_result_spec_amount ("fee_refresh", +                                     &melt->melt_fee), +        GNUNET_PQ_result_spec_end        };        if (GNUNET_OK != -	  GNUNET_PQ_extract_result (result, -				    rs, -				    i)) +          GNUNET_PQ_extract_result (result, +                                    rs, +                                    i))        { -	GNUNET_break (0); -	GNUNET_free (melt); -	chc->status = GNUNET_DB_STATUS_HARD_ERROR; -	return; +        GNUNET_break (0); +        GNUNET_free (melt); +        chc->status = GNUNET_DB_STATUS_HARD_ERROR; +        return;        }        melt->session.coin.coin_pub = *chc->coin_pub;      } @@ -4401,8 +4514,8 @@ add_coin_melt (void *cls,   */  static void  add_coin_refund (void *cls, -		 PGresult *result, -		 unsigned int num_results) +                 PGresult *result, +                 unsigned int num_results)  {    struct CoinHistoryContext *chc = cls; @@ -4415,30 +4528,30 @@ add_coin_refund (void *cls,      refund = GNUNET_new (struct TALER_EXCHANGEDB_Refund);      {        struct GNUNET_PQ_ResultSpec rs[] = { -	GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", -					      &refund->merchant_pub), -	GNUNET_PQ_result_spec_auto_from_type ("merchant_sig", -					      &refund->merchant_sig), -	GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms", -					      &refund->h_contract_terms), -	GNUNET_PQ_result_spec_uint64 ("rtransaction_id", -				      &refund->rtransaction_id), -	TALER_PQ_result_spec_amount ("amount_with_fee", -				     &refund->refund_amount), -	TALER_PQ_result_spec_amount ("fee_refund", -				     &refund->refund_fee), -	GNUNET_PQ_result_spec_end +        GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", +                                              &refund->merchant_pub), +        GNUNET_PQ_result_spec_auto_from_type ("merchant_sig", +                                              &refund->merchant_sig), +        GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms", +                                              &refund->h_contract_terms), +        GNUNET_PQ_result_spec_uint64 ("rtransaction_id", +                                      &refund->rtransaction_id), +        TALER_PQ_result_spec_amount ("amount_with_fee", +                                     &refund->refund_amount), +        TALER_PQ_result_spec_amount ("fee_refund", +                                     &refund->refund_fee), +        GNUNET_PQ_result_spec_end        };        if (GNUNET_OK != -	  GNUNET_PQ_extract_result (result, -				    rs, -				    i)) +          GNUNET_PQ_extract_result (result, +                                    rs, +                                    i))        { -	GNUNET_break (0); -	GNUNET_free (refund); -	chc->status = GNUNET_DB_STATUS_HARD_ERROR; -	return; +        GNUNET_break (0); +        GNUNET_free (refund); +        chc->status = GNUNET_DB_STATUS_HARD_ERROR; +        return;        }        refund->coin.coin_pub = *chc->coin_pub;      } @@ -4471,9 +4584,70 @@ add_coin_refund (void *cls,   * @param num_result the number of results in @a result   */  static void +add_old_coin_payback (void *cls, +                      PGresult *result, +                      unsigned int num_results) +{ +  struct CoinHistoryContext *chc = cls; + +  for (unsigned int i=0;i<num_results;i++) +  { +    struct TALER_EXCHANGEDB_PaybackRefresh *payback; +    struct TALER_EXCHANGEDB_TransactionList *tl; + +    payback = GNUNET_new (struct TALER_EXCHANGEDB_PaybackRefresh); +    { +      struct GNUNET_PQ_ResultSpec rs[] = { +        GNUNET_PQ_result_spec_auto_from_type ("coin_pub", +                                              &payback->coin.coin_pub), +        GNUNET_PQ_result_spec_auto_from_type ("coin_sig", +                                              &payback->coin_sig), +        GNUNET_PQ_result_spec_auto_from_type ("coin_blind", +                                              &payback->coin_blind), +        TALER_PQ_result_spec_amount ("amount", +                                     &payback->value), +        TALER_PQ_result_spec_absolute_time ("timestamp", +                                            &payback->timestamp), +        GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash", +                                              &payback->coin.denom_pub_hash), +        GNUNET_PQ_result_spec_rsa_signature ("denom_sig", +                                             &payback->coin.denom_sig.rsa_signature), +        GNUNET_PQ_result_spec_end +      }; + +      if (GNUNET_OK != +          GNUNET_PQ_extract_result (result, +                                    rs, +                                    i)) +      { +        GNUNET_break (0); +        GNUNET_free (payback); +        chc->status = GNUNET_DB_STATUS_HARD_ERROR; +        return; +      } +      payback->old_coin_pub = *chc->coin_pub; +    } +    tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList); +    tl->next = chc->head; +    tl->type = TALER_EXCHANGEDB_TT_OLD_COIN_PAYBACK; +    tl->details.old_coin_payback = payback; +    chc->head = tl; +  } +} + + +/** + * Function to be called with the results of a SELECT statement + * that has returned @a num_results results. + * + * @param cls closure of type `struct CoinHistoryContext` + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void  add_coin_payback (void *cls, -		  PGresult *result, -		  unsigned int num_results) +                  PGresult *result, +                  unsigned int num_results)  {    struct CoinHistoryContext *chc = cls; @@ -4485,32 +4659,32 @@ add_coin_payback (void *cls,      payback = GNUNET_new (struct TALER_EXCHANGEDB_Payback);      {        struct GNUNET_PQ_ResultSpec rs[] = { -	TALER_PQ_result_spec_amount ("amount", -				     &payback->value), -	GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", -					      &payback->reserve_pub), -	GNUNET_PQ_result_spec_auto_from_type ("coin_blind", -					      &payback->coin_blind), -	GNUNET_PQ_result_spec_auto_from_type ("coin_sig", -					      &payback->coin_sig), -	TALER_PQ_result_spec_absolute_time ("timestamp", -					     &payback->timestamp), -	GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash", -					      &payback->coin.denom_pub_hash), -	GNUNET_PQ_result_spec_rsa_signature ("denom_sig", -					     &payback->coin.denom_sig.rsa_signature), -	GNUNET_PQ_result_spec_end +        TALER_PQ_result_spec_amount ("amount", +                                     &payback->value), +        GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", +                                              &payback->reserve_pub), +        GNUNET_PQ_result_spec_auto_from_type ("coin_blind", +                                              &payback->coin_blind), +        GNUNET_PQ_result_spec_auto_from_type ("coin_sig", +                                              &payback->coin_sig), +        TALER_PQ_result_spec_absolute_time ("timestamp", +                                            &payback->timestamp), +        GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash", +                                              &payback->coin.denom_pub_hash), +        GNUNET_PQ_result_spec_rsa_signature ("denom_sig", +                                             &payback->coin.denom_sig.rsa_signature), +        GNUNET_PQ_result_spec_end        };        if (GNUNET_OK != -	  GNUNET_PQ_extract_result (result, -				    rs, -				    i)) +          GNUNET_PQ_extract_result (result, +                                    rs, +                                    i))        { -	GNUNET_break (0); -	GNUNET_free (payback); -	chc->status = GNUNET_DB_STATUS_HARD_ERROR; -	return; +        GNUNET_break (0); +        GNUNET_free (payback); +        chc->status = GNUNET_DB_STATUS_HARD_ERROR; +        return;        }        payback->coin.coin_pub = *chc->coin_pub;      } @@ -4524,6 +4698,67 @@ add_coin_payback (void *cls,  /** + * Function to be called with the results of a SELECT statement + * that has returned @a num_results results. + * + * @param cls closure of type `struct CoinHistoryContext` + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +add_coin_payback_refresh (void *cls, +                          PGresult *result, +                          unsigned int num_results) +{ +  struct CoinHistoryContext *chc = cls; + +  for (unsigned int i=0;i<num_results;i++) +  { +    struct TALER_EXCHANGEDB_PaybackRefresh *payback; +    struct TALER_EXCHANGEDB_TransactionList *tl; + +    payback = GNUNET_new (struct TALER_EXCHANGEDB_PaybackRefresh); +    { +      struct GNUNET_PQ_ResultSpec rs[] = { +        GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub", +                                              &payback->old_coin_pub), +        GNUNET_PQ_result_spec_auto_from_type ("coin_sig", +                                              &payback->coin_sig), +        GNUNET_PQ_result_spec_auto_from_type ("coin_blind", +                                              &payback->coin_blind), +        TALER_PQ_result_spec_amount ("amount", +                                     &payback->value), +        TALER_PQ_result_spec_absolute_time ("timestamp", +                                            &payback->timestamp), +        GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash", +                                              &payback->coin.denom_pub_hash), +        GNUNET_PQ_result_spec_rsa_signature ("denom_sig", +                                             &payback->coin.denom_sig.rsa_signature), +        GNUNET_PQ_result_spec_end +      }; + +      if (GNUNET_OK != +          GNUNET_PQ_extract_result (result, +                                    rs, +                                    i)) +      { +        GNUNET_break (0); +        GNUNET_free (payback); +        chc->status = GNUNET_DB_STATUS_HARD_ERROR; +        return; +      } +      payback->coin.coin_pub = *chc->coin_pub; +    } +    tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList); +    tl->next = chc->head; +    tl->type = TALER_EXCHANGEDB_TT_PAYBACK_REFRESH; +    tl->details.payback_refresh = payback; +    chc->head = tl; +  } +} + + +/**   * Work we need to do.   */  struct Work @@ -4541,8 +4776,8 @@ struct Work  /** - * Compile a list of all (historic) transactions performed - * with the given coin (/refresh/melt, /deposit and /refund operations). + * Compile a list of all (historic) transactions performed with the given coin + * (/refresh/melt, /deposit, /refund and /payback operations).   *   * @param cls the `struct PostgresClosure` with the plugin-specific state   * @param session database connection @@ -4555,7 +4790,7 @@ postgres_get_coin_transactions (void *cls,                                  struct TALER_EXCHANGEDB_Session *session,                                  const struct TALER_CoinSpendPublicKeyP *coin_pub,                                  int include_payback, -				struct TALER_EXCHANGEDB_TransactionList **tlp) +                                struct TALER_EXCHANGEDB_TransactionList **tlp)  {    static const struct Work work_op[] = {      /** #TALER_EXCHANGEDB_TT_DEPOSIT */ @@ -4567,6 +4802,9 @@ postgres_get_coin_transactions (void *cls,      /** #TALER_EXCHANGEDB_TT_REFUND */      { "get_refunds_by_coin",        &add_coin_refund }, +    /** #TALER_EXCHANGEDB_TT_OLD_COIN_PAYBACK */ +    { "payback_by_old_coin", +      &add_old_coin_payback },      { NULL, NULL }    };    static const struct Work work_wp[] = { @@ -4579,9 +4817,15 @@ postgres_get_coin_transactions (void *cls,      /** #TALER_EXCHANGEDB_TT_REFUND */      { "get_refunds_by_coin",        &add_coin_refund }, +    /** #TALER_EXCHANGEDB_TT_OLD_COIN_PAYBACK */ +    { "payback_by_old_coin", +      &add_old_coin_payback },      /** #TALER_EXCHANGEDB_TT_PAYBACK */      { "payback_by_coin",        &add_coin_payback }, +    /** #TALER_EXCHANGEDB_TT_PAYBACK_REFRESH */ +    { "payback_by_refreshed_coin", +      &add_coin_payback_refresh },      { NULL, NULL }    };    struct CoinHistoryContext chc; @@ -4604,19 +4848,19 @@ postgres_get_coin_transactions (void *cls,    for (unsigned int i=0;NULL != work[i].statement; i++)    {      qs = GNUNET_PQ_eval_prepared_multi_select (session->conn, -					       work[i].statement, -					       params, -					       work[i].cb, -					       &chc); +                                               work[i].statement, +                                               params, +                                               work[i].cb, +                                               &chc);      if ( (0 > qs) ||  	 (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != chc.status) )      {        if (NULL != chc.head) -	common_free_coin_transaction_list (cls, -					   chc.head); +        common_free_coin_transaction_list (cls, +                                           chc.head);        *tlp = NULL;        if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != chc.status) -	qs = chc.status; +        qs = chc.status;        return qs;      }    } @@ -4660,8 +4904,8 @@ struct WireTransferResultContext   */  static void  handle_wt_result (void *cls, -		  PGresult *result, -		  unsigned int num_results) +                  PGresult *result, +                  unsigned int num_results)  {    struct WireTransferResultContext *ctx = cls; @@ -5207,8 +5451,8 @@ postgres_insert_reserve_closed (void *cls,    }    GNUNET_break (GNUNET_NO == ret);    return reserves_update (cls, -			  session, -			  &reserve); +                          session, +                          &reserve);  } @@ -6369,8 +6613,8 @@ struct PaybackSerialContext   */  static void  payback_serial_helper_cb (void *cls, -			  PGresult *result, -			  unsigned int num_results) +                          PGresult *result, +                          unsigned int num_results)  {    struct PaybackSerialContext *psc = cls; @@ -6422,14 +6666,14 @@ payback_serial_helper_cb (void *cls,        return;      }      ret = psc->cb (psc->cb_cls, -		   rowid, -		   timestamp, -		   &amount, -		   &reserve_pub, -		   &coin, +                   rowid, +                   timestamp, +                   &amount, +                   &reserve_pub, +                   &coin,                     &denom_pub, -		   &coin_sig, -		   &coin_blind); +                   &coin_sig, +                   &coin_blind);      GNUNET_PQ_cleanup_result (rs);      if (GNUNET_OK != ret)        break; @@ -6478,6 +6722,147 @@ postgres_select_payback_above_serial_id (void *cls,  /** + * Closure for #payback_refresh_serial_helper_cb(). + */ +struct PaybackRefreshSerialContext +{ + +  /** +   * Callback to call. +   */ +  TALER_EXCHANGEDB_PaybackRefreshCallback cb; + +  /** +   * Closure for @e cb. +   */ +  void *cb_cls; + +  /** +   * Status code, set to #GNUNET_SYSERR on hard errors. +   */ +  int status; +}; + + +/** + * Helper function to be called with the results of a SELECT statement + * that has returned @a num_results results. + * + * @param cls closure of type `struct PaybackRefreshSerialContext` + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +payback_refresh_serial_helper_cb (void *cls, +                                  PGresult *result, +                                  unsigned int num_results) +{ +  struct PaybackRefreshSerialContext *psc = cls; + +  for (unsigned int i=0;i<num_results;i++) +  { +    uint64_t rowid; +    struct TALER_CoinSpendPublicKeyP old_coin_pub; +    struct TALER_CoinPublicInfo coin; +    struct TALER_CoinSpendSignatureP coin_sig; +    struct TALER_DenominationBlindingKeyP coin_blind; +    struct TALER_DenominationPublicKey denom_pub; +    struct TALER_Amount amount; +    struct GNUNET_HashCode h_blind_ev; +    struct GNUNET_TIME_Absolute timestamp; +    struct GNUNET_PQ_ResultSpec rs[] = { +      GNUNET_PQ_result_spec_uint64 ("payback_uuid", +                                    &rowid), +      TALER_PQ_result_spec_absolute_time ("timestamp", +                                           ×tamp), +      GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub", +                                            &old_coin_pub), +      GNUNET_PQ_result_spec_auto_from_type ("coin_pub", +                                            &coin.coin_pub), +      GNUNET_PQ_result_spec_auto_from_type ("coin_sig", +                                            &coin_sig), +      GNUNET_PQ_result_spec_auto_from_type ("coin_blind", +                                            &coin_blind), +      GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev", +                                            &h_blind_ev), +      GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash", +                                            &coin.denom_pub_hash), +      GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", +                                           &denom_pub.rsa_public_key), +      GNUNET_PQ_result_spec_rsa_signature ("denom_sig", +                                           &coin.denom_sig.rsa_signature), +      TALER_PQ_result_spec_amount ("amount", +                                   &amount), +      GNUNET_PQ_result_spec_end +    }; +    int ret; + +    if (GNUNET_OK != +        GNUNET_PQ_extract_result (result, +                                  rs, +                                  i)) +    { +      GNUNET_break (0); +      psc->status = GNUNET_SYSERR; +      return; +    } +    ret = psc->cb (psc->cb_cls, +                   rowid, +                   timestamp, +                   &amount, +                   &old_coin_pub, +                   &coin, +                   &denom_pub, +                   &coin_sig, +                   &coin_blind); +    GNUNET_PQ_cleanup_result (rs); +    if (GNUNET_OK != ret) +      break; +  } +} + + +/** + * Function called to select payback requests the exchange received for + * refreshed coins, ordered by serial ID (monotonically increasing). + * + * @param cls closure + * @param session database connection + * @param serial_id lowest serial ID to include (select larger or equal) + * @param cb function to call for ONE unfinished item + * @param cb_cls closure for @a cb + * @return transaction status code + */ +static enum GNUNET_DB_QueryStatus +postgres_select_payback_refresh_above_serial_id (void *cls, +                                                 struct TALER_EXCHANGEDB_Session *session, +                                                 uint64_t serial_id, +                                                 TALER_EXCHANGEDB_PaybackRefreshCallback cb, +                                                 void *cb_cls) +{ +  struct GNUNET_PQ_QueryParam params[] = { +    GNUNET_PQ_query_param_uint64 (&serial_id), +    GNUNET_PQ_query_param_end +  }; +  struct PaybackRefreshSerialContext psc = { +    .cb = cb, +    .cb_cls = cb_cls, +    .status = GNUNET_OK +  }; +  enum GNUNET_DB_QueryStatus qs; + +  qs = GNUNET_PQ_eval_prepared_multi_select (session->conn, +                                             "payback_refresh_get_incr", +                                             params, +                                             &payback_refresh_serial_helper_cb, +                                             &psc); +  if (GNUNET_OK != psc.status) +    return GNUNET_DB_STATUS_HARD_ERROR; +  return qs; +} + + +/**   * Closure for #reserve_closed_serial_helper_cb().   */  struct ReserveClosedSerialContext @@ -6580,10 +6965,10 @@ reserve_closed_serial_helper_cb (void *cls,   */  static enum GNUNET_DB_QueryStatus  postgres_select_reserve_closed_above_serial_id (void *cls, -						struct TALER_EXCHANGEDB_Session *session, -						uint64_t serial_id, -						TALER_EXCHANGEDB_ReserveClosedCallback cb, -						void *cb_cls) +                                                struct TALER_EXCHANGEDB_Session *session, +                                                uint64_t serial_id, +                                                TALER_EXCHANGEDB_ReserveClosedCallback cb, +                                                void *cb_cls)  {    struct GNUNET_PQ_QueryParam params[] = {      GNUNET_PQ_query_param_uint64 (&serial_id), @@ -6649,17 +7034,10 @@ postgres_insert_payback_request (void *cls,    };    enum GNUNET_DB_QueryStatus qs; -#if 0 -  /* check if the coin is already known */ -  if (0 > (qs = postgres_ensure_coin_known (cls, -                                            session, -                                            coin))) -    return qs; -#endif    /* now store actual payback information */    qs = GNUNET_PQ_eval_prepared_non_select (session->conn, -					   "payback_insert", -					   params); +                                           "payback_insert", +                                           params);    if (0 > qs)    {      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); @@ -6669,8 +7047,8 @@ postgres_insert_payback_request (void *cls,    /* Update reserve balance */    reserve.pub = *reserve_pub;    qs = postgres_reserve_get (cls, -			     session, -			     &reserve); +                             session, +                             &reserve);    if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)    {      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); @@ -6689,8 +7067,8 @@ postgres_insert_payback_request (void *cls,    reserve.expiry = GNUNET_TIME_absolute_max (expiry,                                               reserve.expiry);    qs = reserves_update (cls, -                         session, -                         &reserve); +                        session, +                        &reserve);    if (0 >= qs)    {      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); @@ -6701,6 +7079,57 @@ postgres_insert_payback_request (void *cls,  /** + * Function called to add a request for an emergency payback for a + * refreshed coin.  The funds are to be added back to the original coin + * (which is implied via @a h_blind_ev, see the prepared statement + * "payback_by_old_coin" used in #postgres_get_coin_transactions()). + * + * @param cls closure + * @param session database connection + * @param coin public information about the refreshed coin + * @param coin_sig signature of the coin of type #TALER_SIGNATURE_WALLET_COIN_PAYBACK + * @param coin_blind blinding key of the coin + * @param h_blind_ev blinded envelope, as calculated by the exchange + * @param amount total amount to be paid back + * @param h_blind_ev hash of the blinded coin's envelope (must match reserves_out entry) + * @param timestamp a timestamp to store + * @return transaction result status + */ +static enum GNUNET_DB_QueryStatus +postgres_insert_payback_refresh_request (void *cls, +                                         struct TALER_EXCHANGEDB_Session *session, +                                         const struct TALER_CoinPublicInfo *coin, +                                         const struct TALER_CoinSpendSignatureP *coin_sig, +                                         const struct TALER_DenominationBlindingKeyP *coin_blind, +                                         const struct TALER_Amount *amount, +                                         const struct GNUNET_HashCode *h_blind_ev, +                                         struct GNUNET_TIME_Absolute timestamp) +{ +  struct GNUNET_PQ_QueryParam params[] = { +    GNUNET_PQ_query_param_auto_from_type (&coin->coin_pub), +    GNUNET_PQ_query_param_auto_from_type (coin_sig), +    GNUNET_PQ_query_param_auto_from_type (coin_blind), +    TALER_PQ_query_param_amount (amount), +    TALER_PQ_query_param_absolute_time (×tamp), +    GNUNET_PQ_query_param_auto_from_type (h_blind_ev), +    GNUNET_PQ_query_param_end +  }; +  enum GNUNET_DB_QueryStatus qs; + +  /* now store actual payback information */ +  qs = GNUNET_PQ_eval_prepared_non_select (session->conn, +                                           "payback_refresh_insert", +                                           params); +  if (0 > qs) +  { +    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); +    return qs; +  } +  return qs; +} + + +/**   * Obtain information about which reserve a coin was generated   * from given the hash of the blinded coin.   * @@ -7325,10 +7754,14 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)      = &postgres_select_wire_out_above_serial_id_by_account;    plugin->select_payback_above_serial_id      = &postgres_select_payback_above_serial_id; +  plugin->select_payback_refresh_above_serial_id +    = &postgres_select_payback_refresh_above_serial_id;    plugin->select_reserve_closed_above_serial_id      = &postgres_select_reserve_closed_above_serial_id;    plugin->insert_payback_request      = &postgres_insert_payback_request; +  plugin->insert_payback_refresh_request +    = &postgres_insert_payback_refresh_request;    plugin->get_reserve_by_h_blind      = &postgres_get_reserve_by_h_blind;    plugin->insert_denomination_revocation diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 49aac827..8450fb04 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -234,6 +234,47 @@ struct TALER_EXCHANGEDB_Payback  /** + * Information the exchange records about a /payback-refresh request. + */ +struct TALER_EXCHANGEDB_PaybackRefresh +{ + +  /** +   * Information about the coin that was paid back. +   */ +  struct TALER_CoinPublicInfo coin; + +  /** +   * Blinding factor supplied to prove to the exchange that +   * the coin came from this reserve. +   */ +  struct TALER_DenominationBlindingKeyP coin_blind; + +  /** +   * Signature of the coin of type +   * #TALER_SIGNATURE_WALLET_COIN_PAYBACK. +   */ +  struct TALER_CoinSpendSignatureP coin_sig; + +  /** +   * Public key of the old coin that the refresh'ed coin was paid back to. +   */ +  struct TALER_CoinSpendPublicKeyP old_coin_pub; + +  /** +   * How much was the coin still worth at this time? +   */ +  struct TALER_Amount value; + +  /** +   * When did the /payback operation happen? +   */ +  struct GNUNET_TIME_Absolute timestamp; + +}; + + +/**   * @brief Types of operations on a reserve.   */  enum TALER_EXCHANGEDB_ReserveOperation @@ -572,9 +613,19 @@ enum TALER_EXCHANGEDB_TransactionType {    TALER_EXCHANGEDB_TT_REFUND = 2,    /** +   * /payback-refresh operation (on the old coin, adding to the old coin's value) +   */ +  TALER_EXCHANGEDB_TT_OLD_COIN_PAYBACK = 3, + +  /**     * /payback operation.     */ -  TALER_EXCHANGEDB_TT_PAYBACK = 3 +  TALER_EXCHANGEDB_TT_PAYBACK = 4, + +  /** +   * /payback-refresh operation (on the new coin, eliminating its value) +   */ +  TALER_EXCHANGEDB_TT_PAYBACK_REFRESH = 5  }; @@ -603,24 +654,42 @@ struct TALER_EXCHANGEDB_TransactionList      /**       * Details if transaction was a /deposit operation. +     * (#TALER_EXCHANGEDB_TT_DEPOSIT)       */      struct TALER_EXCHANGEDB_Deposit *deposit;      /**       * Details if transaction was a /refresh/melt operation. +     * (#TALER_EXCHANGEDB_TT_REFRESH_MELT)       */      struct TALER_EXCHANGEDB_RefreshMelt *melt;      /**       * Details if transaction was a /refund operation. +     * (#TALER_EXCHANGEDB_TT_REFUND)       */      struct TALER_EXCHANGEDB_Refund *refund;      /** +     * Details if transaction was a /payback-refund operation where +     * this coin was the OLD coin. +     * (#TALER_EXCHANGEDB_TT_OLD_COIN_PAYBACK). +     */ +    struct TALER_EXCHANGEDB_PaybackRefresh *old_coin_payback; + +    /**       * Details if transaction was a /payback operation. +     * (#TALER_EXCHANGEDB_TT_PAYBACK)       */      struct TALER_EXCHANGEDB_Payback *payback; +    /** +     * Details if transaction was a /payback-refund operation where +     * this coin was the REFRESHED coin. +     * (#TALER_EXCHANGEDB_TT_PAYBACK_REFRESH) +     */ +    struct TALER_EXCHANGEDB_PaybackRefresh *payback_refresh; +    } details;  }; @@ -804,7 +873,7 @@ struct TALER_EXCHANGEDB_RefreshRevealedCoin     * link data, of type #TALER_SIGNATURE_WALLET_COIN_LINK     */    struct TALER_CoinSpendSignatureP orig_coin_link_sig; -   +    /**     * Blinded message to be signed (in envelope), with @e coin_env_size bytes.     */ @@ -1062,6 +1131,35 @@ typedef int                                      const struct TALER_DenominationBlindingKeyP *coin_blind); + +/** + * Function called about paybacks on refreshed coins the exchange has to + * perform. + * + * @param cls closure + * @param rowid row identifier used to uniquely identify the payback operation + * @param timestamp when did we receive the payback request + * @param amount how much should be added back to the reserve + * @param old_coin_pub original coin that was refreshed to create @a coin + * @param coin public information about the coin + * @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_COIN_PAYBACK + * @param coin_blind blinding factor used to blind the coin + * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop + */ +typedef int +(*TALER_EXCHANGEDB_PaybackRefreshCallback)(void *cls, +                                           uint64_t rowid, +                                           struct GNUNET_TIME_Absolute timestamp, +                                           const struct TALER_Amount *amount, +                                           const struct TALER_CoinSpendPublicKeyP *old_coin_pub, +                                           const struct TALER_CoinPublicInfo *coin, +                                           const struct TALER_DenominationPublicKey *denom_pub, +                                           const struct TALER_CoinSpendSignatureP *coin_sig, +                                           const struct TALER_DenominationBlindingKeyP *coin_blind); + + + +  /**   * Function called about reserve closing operations   * the aggregator triggered. @@ -1463,7 +1561,7 @@ struct TALER_EXCHANGEDB_Plugin                          struct TALER_EXCHANGEDB_Session *session,                          const struct TALER_CoinPublicInfo *coin); -   +    /**     * Retrieve information about the given @a coin from the database.     * @@ -2223,6 +2321,25 @@ struct TALER_EXCHANGEDB_Plugin    /** +   * Function called to select payback requests the exchange received for +   * refreshed coins, ordered by serial ID (monotonically increasing). +   * +   * @param cls closure +   * @param session database connection +   * @param serial_id lowest serial ID to include (select larger or equal) +   * @param cb function to call for ONE unfinished item +   * @param cb_cls closure for @a cb +   * @return transaction status code +   */ +  enum GNUNET_DB_QueryStatus +  (*select_payback_refresh_above_serial_id)(void *cls, +                                            struct TALER_EXCHANGEDB_Session *session, +                                            uint64_t serial_id, +                                            TALER_EXCHANGEDB_PaybackRefreshCallback cb, +                                            void *cb_cls); + + +  /**     * Function called to select reserve close operations the aggregator     * triggered, ordered by serial ID (monotonically increasing).     * @@ -2235,18 +2352,15 @@ struct TALER_EXCHANGEDB_Plugin     */    enum GNUNET_DB_QueryStatus    (*select_reserve_closed_above_serial_id)(void *cls, -					   struct TALER_EXCHANGEDB_Session *session, -					   uint64_t serial_id, -					   TALER_EXCHANGEDB_ReserveClosedCallback cb, -					   void *cb_cls); +                                           struct TALER_EXCHANGEDB_Session *session, +                                           uint64_t serial_id, +                                           TALER_EXCHANGEDB_ReserveClosedCallback cb, +                                           void *cb_cls);    /**     * Function called to add a request for an emergency payback for a -   * coin.  The funds are to be added back to the reserve.  The -   * function should return the @a deadline by which the exchange will -   * trigger a wire transfer back to the customer's account for the -   * reserve. +   * coin.  The funds are to be added back to the reserve.     *     * @param cls closure     * @param session database connection @@ -2256,9 +2370,8 @@ struct TALER_EXCHANGEDB_Plugin     * @param coin_blind blinding key of the coin     * @param h_blind_ev blinded envelope, as calculated by the exchange     * @param amount total amount to be paid back -   * @param receiver_account_details who should receive the funds     * @param h_blind_ev hash of the blinded coin's envelope (must match reserves_out entry) -   * @param now timestamp to store +   * @param timestamp the timestamp to store     * @return transaction result status     */    enum GNUNET_DB_QueryStatus @@ -2274,6 +2387,32 @@ struct TALER_EXCHANGEDB_Plugin    /** +   * Function called to add a request for an emergency payback for a +   * refreshed coin.  The funds are to be added back to the original coin. +   * +   * @param cls closure +   * @param session database connection +   * @param coin public information about the refreshed coin +   * @param coin_sig signature of the coin of type #TALER_SIGNATURE_WALLET_COIN_PAYBACK +   * @param coin_blind blinding key of the coin +   * @param h_blind_ev blinded envelope, as calculated by the exchange +   * @param amount total amount to be paid back +   * @param h_blind_ev hash of the blinded coin's envelope (must match reserves_out entry) +   * @param timestamp a timestamp to store +   * @return transaction result status +   */ +  enum GNUNET_DB_QueryStatus +  (*insert_payback_refresh_request)(void *cls, +                                    struct TALER_EXCHANGEDB_Session *session, +                                    const struct TALER_CoinPublicInfo *coin, +                                    const struct TALER_CoinSpendSignatureP *coin_sig, +                                    const struct TALER_DenominationBlindingKeyP *coin_blind, +                                    const struct TALER_Amount *amount, +                                    const struct GNUNET_HashCode *h_blind_ev, +                                    struct GNUNET_TIME_Absolute timestamp); + + +  /**     * Obtain information about which reserve a coin was generated     * from given the hash of the blinded coin.     * @@ -2323,7 +2462,7 @@ struct TALER_EXCHANGEDB_Plugin                                   struct TALER_EXCHANGEDB_Session *session,                                   const struct GNUNET_HashCode *denom_pub_hash,                                   struct TALER_MasterSignatureP *master_sig, -				 uint64_t *rowid); +                                 uint64_t *rowid);    /** @@ -2341,11 +2480,11 @@ struct TALER_EXCHANGEDB_Plugin     */    enum GNUNET_DB_QueryStatus    (*select_deposits_missing_wire)(void *cls, -				  struct TALER_EXCHANGEDB_Session *session, -				  struct GNUNET_TIME_Absolute start_date, -				  struct GNUNET_TIME_Absolute end_date, -				  TALER_EXCHANGEDB_WireMissingCallback cb, -				  void *cb_cls); +                                  struct TALER_EXCHANGEDB_Session *session, +                                  struct GNUNET_TIME_Absolute start_date, +                                  struct GNUNET_TIME_Absolute end_date, +                                  TALER_EXCHANGEDB_WireMissingCallback cb, +                                  void *cb_cls);    /**     * Insert a merchant into the KYC monitor table, namely it  | 
