diff options
-rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 26 | ||||
-rw-r--r-- | src/exchangedb/test_exchangedb.c | 128 | ||||
-rw-r--r-- | src/include/taler_exchangedb_plugin.h | 2 |
3 files changed, 148 insertions, 8 deletions
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 1f1e5f119..c9c3d5fd4 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -3373,9 +3373,7 @@ static void free_dpk_result (struct TALER_DenominationPublicKey *denom_pubs, unsigned int denom_pubs_len) { - unsigned int i; - - for (i=0;i<denom_pubs_len;i++) + for (unsigned int i=0;i<denom_pubs_len;i++) { GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[i].rsa_public_key); denom_pubs[i].rsa_public_key = NULL; @@ -3724,10 +3722,9 @@ postgres_get_refresh_transfer_public_key (void *cls, /** - * Insert signature of a new coin generated during refresh into + * Get signature of a new coin generated during refresh into * the database indexed by the refresh session and the index - * of the coin. This data is later used should an old coin - * be used to try to obtain the private keys during "/refresh/link". + * of the coin. * * @param cls the `struct PostgresClosure` with the plugin-specific state * @param session database connection @@ -5988,7 +5985,7 @@ postgres_get_reserve_by_h_blind (void *cls, * @param denom_pub_hash hash of the revoked denomination key * @param master_sig signature affirming the revocation * @return #GNUNET_OK on success, - * #GNUNET_NO if the entry already exists + * #GNUNET_NO if the entry already exists (transaction must be rolled back!) * #GNUNET_SYSERR on DB errors */ static int @@ -6010,6 +6007,21 @@ postgres_insert_denomination_revocation (void *cls, params); if (PGRES_COMMAND_OK != PQresultStatus (result)) { + const char *efield; + + efield = PQresultErrorField (result, + PG_DIAG_SQLSTATE); + if ( (PGRES_FATAL_ERROR == PQresultStatus(result)) && + (NULL != strstr ("23505", /* unique violation */ + efield)) ) + { + /* This means we had the same reserve/justification/details + before */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Uniqueness violation, revocation details already known\n"); + PQclear (result); + return GNUNET_NO; + } ret = GNUNET_SYSERR; BREAK_DB_ERR (result, session->conn); } diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c index 5175ef4fb..f3a5adcb8 100644 --- a/src/exchangedb/test_exchangedb.c +++ b/src/exchangedb/test_exchangedb.c @@ -663,18 +663,35 @@ test_melting (struct TALER_EXCHANGEDB_Session *session) for (cnt=0; cnt < MELT_NEW_COINS; cnt++) { struct GNUNET_HashCode hc; + struct TALER_DenominationSignature test_sig; RND_BLK (&hc); ev_sigs[cnt].rsa_signature = GNUNET_CRYPTO_rsa_sign_fdh (new_dkp[cnt]->priv.rsa_private_key, &hc); GNUNET_assert (NULL != ev_sigs[cnt].rsa_signature); + FAILIF (GNUNET_NO != + plugin->get_refresh_out (plugin->cls, + session, + &session_hash, + cnt, + &test_sig)); FAILIF (GNUNET_OK != plugin->insert_refresh_out (plugin->cls, session, &session_hash, cnt, &ev_sigs[cnt])); + FAILIF (GNUNET_OK != + plugin->get_refresh_out (plugin->cls, + session, + &session_hash, + cnt, + &test_sig)); + FAILIF (0 != + GNUNET_CRYPTO_rsa_signature_cmp (test_sig.rsa_signature, + ev_sigs[cnt].rsa_signature)); + GNUNET_CRYPTO_rsa_signature_free (test_sig.rsa_signature); } ldl = plugin->get_link_data_list (plugin->cls, @@ -706,6 +723,18 @@ test_melting (struct TALER_EXCHANGEDB_Session *session) ldl); { + /* Just to test fetching a coin with melt history */ + struct TALER_EXCHANGEDB_TransactionList *tl; + + tl = plugin->get_coin_transactions (plugin->cls, + session, + &meltp->coin.coin_pub); + plugin->free_coin_transaction_list (plugin->cls, + tl); + } + + + { int ok; ok = GNUNET_NO; @@ -1338,7 +1367,38 @@ test_wire_out (struct TALER_EXCHANGEDB_Session *session, } +/** + * Function called about paybacks the exchange has to perform. + * + * @param cls closure with the expected value for @a coin_blind + * @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 reserve_pub public key of the reserve + * @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 + */ +static int +payback_cb (void *cls, + uint64_t rowid, + struct GNUNET_TIME_Absolute timestamp, + const struct TALER_Amount *amount, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_CoinPublicInfo *coin, + const struct TALER_CoinSpendSignatureP *coin_sig, + const struct TALER_DenominationBlindingKeyP *coin_blind) +{ + const struct TALER_DenominationBlindingKeyP *cb = cls; + FAILIF (0 != memcmp (cb, + coin_blind, + sizeof (*cb))); + return GNUNET_OK; + drop: + return GNUNET_SYSERR; +} /** @@ -1355,7 +1415,10 @@ run (void *cls) struct GNUNET_TIME_Absolute deadline; struct TALER_DenominationBlindingKeyP coin_blind; struct TALER_ReservePublicKeyP reserve_pub; + struct TALER_ReservePublicKeyP reserve_pub2; struct DenomKeyPair *dkp; + struct GNUNET_HashCode dkp_pub_hash; + struct TALER_MasterSignatureP master_sig; struct TALER_EXCHANGEDB_CollectableBlindcoin cbc; struct TALER_EXCHANGEDB_CollectableBlindcoin cbc2; struct TALER_EXCHANGEDB_ReserveHistory *rh; @@ -1407,6 +1470,14 @@ run (void *cls) result = 77; goto drop; } + + /* test DB is empty */ + FAILIF (GNUNET_NO != + plugin->select_payback_above_serial_id (plugin->cls, + session, + 0, + &payback_cb, + NULL)); RND_BLK (&reserve_pub); GNUNET_assert (GNUNET_OK == TALER_string_to_amount (CURRENCY ":1.000010", @@ -1473,6 +1544,8 @@ run (void *cls) &fee_deposit, &fee_refresh, &fee_refund); + GNUNET_CRYPTO_rsa_public_key_hash (dkp->pub.rsa_public_key, + &dkp_pub_hash); RND_BLK(&cbc.h_coin_envelope); RND_BLK(&cbc.reserve_sig); cbc.denom_pub = dkp->pub; @@ -1493,6 +1566,16 @@ run (void *cls) value.value, value.fraction, value.currency)); + + FAILIF (GNUNET_YES != + plugin->get_reserve_by_h_blind (plugin->cls, + session, + &cbc.h_coin_envelope, + &reserve_pub2)); + FAILIF (0 != memcmp (&reserve_pub, + &reserve_pub2, + sizeof (reserve_pub))); + FAILIF (GNUNET_YES != plugin->get_withdraw_info (plugin->cls, session, @@ -1715,6 +1798,43 @@ run (void *cls) &refund)); + /* test payback / revocation */ + RND_BLK (&master_sig); + FAILIF (GNUNET_OK != + plugin->insert_denomination_revocation (plugin->cls, + session, + &dkp_pub_hash, + &master_sig)); + FAILIF (GNUNET_OK != + plugin->commit (plugin->cls, + session)); + FAILIF (GNUNET_OK != + plugin->start (plugin->cls, + session)); + FAILIF (GNUNET_NO != + plugin->insert_denomination_revocation (plugin->cls, + session, + &dkp_pub_hash, + &master_sig)); + plugin->rollback (plugin->cls, + session); + FAILIF (GNUNET_OK != + plugin->start (plugin->cls, + session)); + { + struct TALER_MasterSignatureP msig; + + FAILIF (GNUNET_OK != + plugin->get_denomination_revocation (plugin->cls, + session, + &dkp_pub_hash, + &msig)); + FAILIF (0 != memcmp (&msig, + &master_sig, + sizeof (msig))); + } + + RND_BLK (&coin_sig); RND_BLK (&coin_blind); FAILIF (GNUNET_OK != @@ -1728,6 +1848,13 @@ run (void *cls) &cbc.h_coin_envelope, deadline)); + FAILIF (GNUNET_OK != + plugin->select_payback_above_serial_id (plugin->cls, + session, + 0, + &payback_cb, + &coin_blind)); + auditor_row_cnt = 0; FAILIF (GNUNET_OK != plugin->select_refunds_above_serial_id (plugin->cls, @@ -1856,6 +1983,7 @@ run (void *cls) FAILIF (GNUNET_OK != test_wire_fees (session)); + result = 0; drop: diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index a5295378b..a287ea563 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -2022,7 +2022,7 @@ struct TALER_EXCHANGEDB_Plugin * @param denom_pub_hash hash of the revoked denomination key * @param master_sig signature affirming the revocation * @return #GNUNET_OK on success, - * #GNUNET_NO if the entry already exists + * #GNUNET_NO if the entry already exists (transaction must be rolled back!) * #GNUNET_SYSERR on DB errors */ int |