-correctly implement CS idempotency check on withdraw
This commit is contained in:
parent
8ecbdeb55b
commit
ef938e0f7a
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of TALER
|
This file is part of TALER
|
||||||
Copyright (C) 2017-2021 Taler Systems SA
|
Copyright (C) 2017-2022 Taler Systems SA
|
||||||
|
|
||||||
TALER is free software; you can redistribute it and/or modify it under the
|
TALER is free software; you can redistribute it and/or modify it under the
|
||||||
terms of the GNU Affero General Public License as published by the Free Software
|
terms of the GNU Affero General Public License as published by the Free Software
|
||||||
@ -40,9 +40,9 @@
|
|||||||
struct RecoupContext
|
struct RecoupContext
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Hash of the blinded coin.
|
* Hash identifying the withdraw request.
|
||||||
*/
|
*/
|
||||||
struct TALER_BlindedCoinHash h_blind;
|
struct TALER_WithdrawIdentificationHash wih;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set by #recoup_transaction() to the reserve that will
|
* Set by #recoup_transaction() to the reserve that will
|
||||||
@ -273,9 +273,9 @@ verify_and_execute_recoup (
|
|||||||
blinded_planchet.details.cs_blinded_planchet.nonce
|
blinded_planchet.details.cs_blinded_planchet.nonce
|
||||||
= *nonce;
|
= *nonce;
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_coin_ev_hash (&blinded_planchet,
|
TALER_withdraw_request_hash (&blinded_planchet,
|
||||||
&coin->denom_pub_hash,
|
&coin->denom_pub_hash,
|
||||||
&pc.h_blind))
|
&pc.wih))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
return TALER_MHD_reply_with_error (connection,
|
return TALER_MHD_reply_with_error (connection,
|
||||||
@ -308,10 +308,10 @@ verify_and_execute_recoup (
|
|||||||
{
|
{
|
||||||
enum GNUNET_DB_QueryStatus qs;
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
|
|
||||||
qs = TEH_plugin->get_reserve_by_h_blind (TEH_plugin->cls,
|
qs = TEH_plugin->get_reserve_by_wih (TEH_plugin->cls,
|
||||||
&pc.h_blind,
|
&pc.wih,
|
||||||
&pc.reserve_pub,
|
&pc.reserve_pub,
|
||||||
&pc.reserve_out_serial_id);
|
&pc.reserve_out_serial_id);
|
||||||
if (0 > qs)
|
if (0 > qs)
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -319,13 +319,13 @@ verify_and_execute_recoup (
|
|||||||
connection,
|
connection,
|
||||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||||
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
||||||
"get_reserve_by_h_blind");
|
"get_reserve_by_wih");
|
||||||
}
|
}
|
||||||
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
|
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
"Recoup requested for unknown envelope %s\n",
|
"Recoup requested for unknown envelope %s\n",
|
||||||
GNUNET_h2s (&pc.h_blind.hash));
|
GNUNET_h2s (&pc.wih.hash));
|
||||||
return TALER_MHD_reply_with_error (
|
return TALER_MHD_reply_with_error (
|
||||||
connection,
|
connection,
|
||||||
MHD_HTTP_NOT_FOUND,
|
MHD_HTTP_NOT_FOUND,
|
||||||
|
@ -91,6 +91,11 @@ reply_withdraw_insufficient_funds (
|
|||||||
struct WithdrawContext
|
struct WithdrawContext
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash that uniquely identifies the withdraw request.
|
||||||
|
*/
|
||||||
|
struct TALER_WithdrawIdentificationHash wih;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash of the (blinded) message to be signed by the Exchange.
|
* Hash of the (blinded) message to be signed by the Exchange.
|
||||||
*/
|
*/
|
||||||
@ -155,6 +160,7 @@ withdraw_transaction (void *cls,
|
|||||||
|
|
||||||
now = GNUNET_TIME_timestamp_get ();
|
now = GNUNET_TIME_timestamp_get ();
|
||||||
qs = TEH_plugin->do_withdraw (TEH_plugin->cls,
|
qs = TEH_plugin->do_withdraw (TEH_plugin->cls,
|
||||||
|
&wc->wih,
|
||||||
&wc->collectable,
|
&wc->collectable,
|
||||||
now,
|
now,
|
||||||
&found,
|
&found,
|
||||||
@ -294,7 +300,7 @@ check_request_idempotent (struct TEH_RequestContext *rc,
|
|||||||
enum GNUNET_DB_QueryStatus qs;
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
|
|
||||||
qs = TEH_plugin->get_withdraw_info (TEH_plugin->cls,
|
qs = TEH_plugin->get_withdraw_info (TEH_plugin->cls,
|
||||||
&wc->collectable.h_coin_envelope,
|
&wc->wih,
|
||||||
&wc->collectable);
|
&wc->collectable);
|
||||||
if (0 > qs)
|
if (0 > qs)
|
||||||
{
|
{
|
||||||
@ -496,7 +502,18 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
|
|||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: if CS: check nonce for reuse
|
if (GNUNET_OK !=
|
||||||
|
TALER_withdraw_request_hash (&wc.blinded_planchet,
|
||||||
|
&wc.collectable.denom_pub_hash,
|
||||||
|
&wc.wih))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
GNUNET_JSON_parse_free (spec);
|
||||||
|
return TALER_MHD_reply_with_error (rc->connection,
|
||||||
|
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||||
|
TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Sign before transaction! */
|
/* Sign before transaction! */
|
||||||
ec = TEH_keys_denomination_sign (
|
ec = TEH_keys_denomination_sign (
|
||||||
@ -535,10 +552,6 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
|
|||||||
/* Clean up and send back final response */
|
/* Clean up and send back final response */
|
||||||
GNUNET_JSON_parse_free (spec);
|
GNUNET_JSON_parse_free (spec);
|
||||||
|
|
||||||
// FIXME: in CS-case, we MUST re-transmit any _existing_ signature
|
|
||||||
// (if database had a record matching the nonce)
|
|
||||||
// instead of sending a 'fresh' one back (as c0/c1 may differ in
|
|
||||||
// a client attack!
|
|
||||||
{
|
{
|
||||||
MHD_RESULT ret;
|
MHD_RESULT ret;
|
||||||
|
|
||||||
|
@ -196,7 +196,8 @@ CREATE INDEX IF NOT EXISTS reserves_close_by_reserve_pub_index
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS reserves_out
|
CREATE TABLE IF NOT EXISTS reserves_out
|
||||||
(reserve_out_serial_id BIGSERIAL -- UNIQUE
|
(reserve_out_serial_id BIGSERIAL -- UNIQUE
|
||||||
,h_blind_ev BYTEA PRIMARY KEY CHECK (LENGTH(h_blind_ev)=64)
|
,wih BYTEA PRIMARY KEY CHECK (LENGTH(wih)=64)
|
||||||
|
,h_blind_ev BYTEA CHECK (LENGTH(h_blind_ev)=64) -- UNIQUE
|
||||||
,denominations_serial INT8 NOT NULL REFERENCES denominations (denominations_serial)
|
,denominations_serial INT8 NOT NULL REFERENCES denominations (denominations_serial)
|
||||||
,denom_sig BYTEA NOT NULL
|
,denom_sig BYTEA NOT NULL
|
||||||
,reserve_uuid INT8 NOT NULL -- REFERENCES reserves (reserve_uuid) ON DELETE CASCADE
|
,reserve_uuid INT8 NOT NULL -- REFERENCES reserves (reserve_uuid) ON DELETE CASCADE
|
||||||
@ -205,9 +206,11 @@ CREATE TABLE IF NOT EXISTS reserves_out
|
|||||||
,amount_with_fee_val INT8 NOT NULL
|
,amount_with_fee_val INT8 NOT NULL
|
||||||
,amount_with_fee_frac INT4 NOT NULL
|
,amount_with_fee_frac INT4 NOT NULL
|
||||||
)
|
)
|
||||||
PARTITION BY HASH (h_blind_ev);
|
PARTITION BY HASH (wih);
|
||||||
COMMENT ON TABLE reserves_out
|
COMMENT ON TABLE reserves_out
|
||||||
IS 'Withdraw operations performed on reserves.';
|
IS 'Withdraw operations performed on reserves.';
|
||||||
|
COMMENT ON COLUMN reserves_out.wih
|
||||||
|
IS 'Hash that uniquely identifies the withdraw request. Used to detect request replays (crucial for CS) and to check the withdraw existed during recoup.';
|
||||||
COMMENT ON COLUMN reserves_out.h_blind_ev
|
COMMENT ON COLUMN reserves_out.h_blind_ev
|
||||||
IS 'Hash of the blinded coin, used as primary key here so that broken clients that use a non-random coin or blinding factor fail to withdraw (otherwise they would fail on deposit when the coin is not unique there).';
|
IS 'Hash of the blinded coin, used as primary key here so that broken clients that use a non-random coin or blinding factor fail to withdraw (otherwise they would fail on deposit when the coin is not unique there).';
|
||||||
COMMENT ON COLUMN reserves_out.denominations_serial
|
COMMENT ON COLUMN reserves_out.denominations_serial
|
||||||
@ -637,7 +640,7 @@ COMMENT ON TABLE recoup
|
|||||||
COMMENT ON COLUMN recoup.known_coin_id
|
COMMENT ON COLUMN recoup.known_coin_id
|
||||||
IS 'Coin that is being debited in the recoup. Do not CASCADE ON DROP on the coin_pub, as we may keep the coin alive!';
|
IS 'Coin that is being debited in the recoup. Do not CASCADE ON DROP on the coin_pub, as we may keep the coin alive!';
|
||||||
COMMENT ON COLUMN recoup.reserve_out_serial_id
|
COMMENT ON COLUMN recoup.reserve_out_serial_id
|
||||||
IS 'Identifies the h_blind_ev of the recouped coin and provides the link to the credited reserve.';
|
IS 'Identifies the wih of the recouped coin and provides the link to the credited reserve.';
|
||||||
COMMENT ON COLUMN recoup.coin_sig
|
COMMENT ON COLUMN recoup.coin_sig
|
||||||
IS 'Signature by the coin affirming the recoup, of type TALER_SIGNATURE_WALLET_COIN_RECOUP';
|
IS 'Signature by the coin affirming the recoup, of type TALER_SIGNATURE_WALLET_COIN_RECOUP';
|
||||||
COMMENT ON COLUMN recoup.coin_blind
|
COMMENT ON COLUMN recoup.coin_blind
|
||||||
@ -812,6 +815,7 @@ CREATE INDEX IF NOT EXISTS revolving_work_shards_by_job_name_active_last_attempt
|
|||||||
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION exchange_do_withdraw(
|
CREATE OR REPLACE FUNCTION exchange_do_withdraw(
|
||||||
|
IN in_wih BYTEA,
|
||||||
IN amount_val INT8,
|
IN amount_val INT8,
|
||||||
IN amount_frac INT4,
|
IN amount_frac INT4,
|
||||||
IN h_denom_pub BYTEA,
|
IN h_denom_pub BYTEA,
|
||||||
@ -825,7 +829,8 @@ CREATE OR REPLACE FUNCTION exchange_do_withdraw(
|
|||||||
OUT balance_ok BOOLEAN,
|
OUT balance_ok BOOLEAN,
|
||||||
OUT kycok BOOLEAN,
|
OUT kycok BOOLEAN,
|
||||||
OUT account_uuid INT8,
|
OUT account_uuid INT8,
|
||||||
OUT ruuid INT8)
|
OUT ruuid INT8,
|
||||||
|
OUT out_denom_sig BYTEA)
|
||||||
LANGUAGE plpgsql
|
LANGUAGE plpgsql
|
||||||
AS $$
|
AS $$
|
||||||
DECLARE
|
DECLARE
|
||||||
@ -838,7 +843,7 @@ DECLARE
|
|||||||
reserve_frac INT4;
|
reserve_frac INT4;
|
||||||
BEGIN
|
BEGIN
|
||||||
-- Shards: reserves by reserve_pub (SELECT)
|
-- Shards: reserves by reserve_pub (SELECT)
|
||||||
-- reserves_out (INSERT, with CONFLICT detection) by h_blind_ev
|
-- reserves_out (INSERT, with CONFLICT detection) by wih
|
||||||
-- reserves by reserve_pub (UPDATE)
|
-- reserves by reserve_pub (UPDATE)
|
||||||
-- reserves_in by reserve_pub (SELECT)
|
-- reserves_in by reserve_pub (SELECT)
|
||||||
-- wire_targets by wire_target_serial_id
|
-- wire_targets by wire_target_serial_id
|
||||||
@ -887,6 +892,7 @@ END IF;
|
|||||||
-- the query successful due to idempotency.
|
-- the query successful due to idempotency.
|
||||||
INSERT INTO reserves_out
|
INSERT INTO reserves_out
|
||||||
(h_blind_ev
|
(h_blind_ev
|
||||||
|
,wih
|
||||||
,denominations_serial
|
,denominations_serial
|
||||||
,denom_sig
|
,denom_sig
|
||||||
,reserve_uuid
|
,reserve_uuid
|
||||||
@ -896,6 +902,7 @@ INSERT INTO reserves_out
|
|||||||
,amount_with_fee_frac)
|
,amount_with_fee_frac)
|
||||||
VALUES
|
VALUES
|
||||||
(h_coin_envelope
|
(h_coin_envelope
|
||||||
|
,in_wih
|
||||||
,denom_serial
|
,denom_serial
|
||||||
,denom_sig
|
,denom_sig
|
||||||
,ruuid
|
,ruuid
|
||||||
@ -908,6 +915,25 @@ ON CONFLICT DO NOTHING;
|
|||||||
IF NOT FOUND
|
IF NOT FOUND
|
||||||
THEN
|
THEN
|
||||||
-- idempotent query, all constraints must be satisfied
|
-- idempotent query, all constraints must be satisfied
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
denom_sig
|
||||||
|
INTO
|
||||||
|
out_denom_sig
|
||||||
|
FROM reserves_in
|
||||||
|
WHERE wih=in_wih
|
||||||
|
LIMIT 1; -- limit 1 should not be required (without p2p transfers)
|
||||||
|
|
||||||
|
IF NOT FOUND
|
||||||
|
THEN
|
||||||
|
reserve_found=FALSE;
|
||||||
|
balance_ok=FALSE;
|
||||||
|
kycok=FALSE;
|
||||||
|
account_uuid=0;
|
||||||
|
ruuid=0;
|
||||||
|
ASSERT false, 'internal logic error';
|
||||||
|
END IF;
|
||||||
|
|
||||||
reserve_found=TRUE;
|
reserve_found=TRUE;
|
||||||
balance_ok=TRUE;
|
balance_ok=TRUE;
|
||||||
kycok=TRUE;
|
kycok=TRUE;
|
||||||
@ -967,9 +993,13 @@ SELECT
|
|||||||
WHERE reserve_pub=rpub
|
WHERE reserve_pub=rpub
|
||||||
LIMIT 1; -- limit 1 should not be required (without p2p transfers)
|
LIMIT 1; -- limit 1 should not be required (without p2p transfers)
|
||||||
|
|
||||||
|
-- Return denomination signature as result that
|
||||||
|
-- was given as the argument.
|
||||||
|
out_denom_sig=denom_sig;
|
||||||
|
|
||||||
END $$;
|
END $$;
|
||||||
|
|
||||||
COMMENT ON FUNCTION exchange_do_withdraw(INT8, INT4, BYTEA, BYTEA, BYTEA, BYTEA, BYTEA, INT8, INT8)
|
COMMENT ON FUNCTION exchange_do_withdraw(BYTEA, INT8, INT4, BYTEA, BYTEA, BYTEA, BYTEA, BYTEA, INT8, INT8)
|
||||||
IS 'Checks whether the reserve has sufficient balance for a withdraw operation (or the request is repeated and was previously approved) and if so updates the database with the result';
|
IS 'Checks whether the reserve has sufficient balance for a withdraw operation (or the request is repeated and was previously approved) and if so updates the database with the result';
|
||||||
|
|
||||||
|
|
||||||
|
@ -560,13 +560,6 @@ prepare_statements (struct PostgresClosure *pg)
|
|||||||
" ON (wire_source_serial_id = wire_target_serial_id)"
|
" ON (wire_source_serial_id = wire_target_serial_id)"
|
||||||
" WHERE reserve_pub=$1;",
|
" WHERE reserve_pub=$1;",
|
||||||
1),
|
1),
|
||||||
/* Lock withdraw table; NOTE: we may want to eventually shard the
|
|
||||||
deposit table to avoid this lock being the main point of
|
|
||||||
contention limiting transaction performance. */
|
|
||||||
GNUNET_PQ_make_prepare (
|
|
||||||
"lock_withdraw",
|
|
||||||
"LOCK TABLE reserves_out;",
|
|
||||||
0),
|
|
||||||
/* Used in #postgres_do_withdraw() to store
|
/* Used in #postgres_do_withdraw() to store
|
||||||
the signature of a blinded coin with the blinded coin's
|
the signature of a blinded coin with the blinded coin's
|
||||||
details before returning it during /reserve/withdraw. We store
|
details before returning it during /reserve/withdraw. We store
|
||||||
@ -582,9 +575,10 @@ prepare_statements (struct PostgresClosure *pg)
|
|||||||
",kycok AS kyc_ok"
|
",kycok AS kyc_ok"
|
||||||
",account_uuid AS payment_target_uuid"
|
",account_uuid AS payment_target_uuid"
|
||||||
",ruuid"
|
",ruuid"
|
||||||
|
",out_denom_sig"
|
||||||
" FROM exchange_do_withdraw"
|
" FROM exchange_do_withdraw"
|
||||||
" ($1,$2,$3,$4,$5,$6,$7,$8,$9);",
|
" ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);",
|
||||||
9),
|
10),
|
||||||
/* Used in #postgres_do_withdraw_limit_check() to check
|
/* Used in #postgres_do_withdraw_limit_check() to check
|
||||||
if the withdrawals remain below the limit under which
|
if the withdrawals remain below the limit under which
|
||||||
KYC is not required. */
|
KYC is not required. */
|
||||||
@ -659,6 +653,7 @@ prepare_statements (struct PostgresClosure *pg)
|
|||||||
",reserve_sig"
|
",reserve_sig"
|
||||||
",reserves.reserve_pub"
|
",reserves.reserve_pub"
|
||||||
",execution_date"
|
",execution_date"
|
||||||
|
",h_blind_ev"
|
||||||
",amount_with_fee_val"
|
",amount_with_fee_val"
|
||||||
",amount_with_fee_frac"
|
",amount_with_fee_frac"
|
||||||
",denom.fee_withdraw_val"
|
",denom.fee_withdraw_val"
|
||||||
@ -668,7 +663,7 @@ prepare_statements (struct PostgresClosure *pg)
|
|||||||
" USING (reserve_uuid)"
|
" USING (reserve_uuid)"
|
||||||
" JOIN denominations denom"
|
" JOIN denominations denom"
|
||||||
" USING (denominations_serial)"
|
" USING (denominations_serial)"
|
||||||
" WHERE h_blind_ev=$1;",
|
" WHERE wih=$1;",
|
||||||
1),
|
1),
|
||||||
/* Used during #postgres_get_reserve_history() to
|
/* Used during #postgres_get_reserve_history() to
|
||||||
obtain all of the /reserve/withdraw operations that
|
obtain all of the /reserve/withdraw operations that
|
||||||
@ -1671,16 +1666,16 @@ prepare_statements (struct PostgresClosure *pg)
|
|||||||
" ON (denoms.denominations_serial = coins.denominations_serial)"
|
" ON (denoms.denominations_serial = coins.denominations_serial)"
|
||||||
" WHERE coins.coin_pub=$1;",
|
" WHERE coins.coin_pub=$1;",
|
||||||
1),
|
1),
|
||||||
/* Used in #postgres_get_reserve_by_h_blind() */
|
/* Used in #postgres_get_reserve_by_wih() */
|
||||||
GNUNET_PQ_make_prepare (
|
GNUNET_PQ_make_prepare (
|
||||||
"reserve_by_h_blind",
|
"reserve_by_wih",
|
||||||
"SELECT"
|
"SELECT"
|
||||||
" reserves.reserve_pub"
|
" reserves.reserve_pub"
|
||||||
",reserve_out_serial_id"
|
",reserve_out_serial_id"
|
||||||
" FROM reserves_out"
|
" FROM reserves_out"
|
||||||
" JOIN reserves"
|
" JOIN reserves"
|
||||||
" USING (reserve_uuid)"
|
" USING (reserve_uuid)"
|
||||||
" WHERE h_blind_ev=$1"
|
" WHERE wih=$1"
|
||||||
" LIMIT 1;",
|
" LIMIT 1;",
|
||||||
1),
|
1),
|
||||||
/* Used in #postgres_get_old_coin_by_h_blind() */
|
/* Used in #postgres_get_old_coin_by_h_blind() */
|
||||||
@ -4304,8 +4299,7 @@ postgres_reserves_in_insert (void *cls,
|
|||||||
* key of the hash of the blinded message.
|
* key of the hash of the blinded message.
|
||||||
*
|
*
|
||||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||||
* @param h_blind hash of the blinded coin to be signed (will match
|
* @param wih hash that uniquely identifies the withdraw operation
|
||||||
* `h_coin_envelope` in the @a collectable to be returned)
|
|
||||||
* @param collectable corresponding collectable coin (blind signature)
|
* @param collectable corresponding collectable coin (blind signature)
|
||||||
* if a coin is found
|
* if a coin is found
|
||||||
* @return statement execution status
|
* @return statement execution status
|
||||||
@ -4313,12 +4307,12 @@ postgres_reserves_in_insert (void *cls,
|
|||||||
static enum GNUNET_DB_QueryStatus
|
static enum GNUNET_DB_QueryStatus
|
||||||
postgres_get_withdraw_info (
|
postgres_get_withdraw_info (
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_BlindedCoinHash *h_blind,
|
const struct TALER_WithdrawIdentificationHash *wih,
|
||||||
struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable)
|
struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable)
|
||||||
{
|
{
|
||||||
struct PostgresClosure *pg = cls;
|
struct PostgresClosure *pg = cls;
|
||||||
struct GNUNET_PQ_QueryParam params[] = {
|
struct GNUNET_PQ_QueryParam params[] = {
|
||||||
GNUNET_PQ_query_param_auto_from_type (h_blind),
|
GNUNET_PQ_query_param_auto_from_type (wih),
|
||||||
GNUNET_PQ_query_param_end
|
GNUNET_PQ_query_param_end
|
||||||
};
|
};
|
||||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
@ -4330,24 +4324,15 @@ postgres_get_withdraw_info (
|
|||||||
&collectable->reserve_sig),
|
&collectable->reserve_sig),
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
|
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
|
||||||
&collectable->reserve_pub),
|
&collectable->reserve_pub),
|
||||||
|
GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
|
||||||
|
&collectable->h_coin_envelope),
|
||||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
||||||
&collectable->amount_with_fee),
|
&collectable->amount_with_fee),
|
||||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_withdraw",
|
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_withdraw",
|
||||||
&collectable->withdraw_fee),
|
&collectable->withdraw_fee),
|
||||||
GNUNET_PQ_result_spec_end
|
GNUNET_PQ_result_spec_end
|
||||||
};
|
};
|
||||||
#if EXPLICIT_LOCKS
|
|
||||||
struct GNUNET_PQ_QueryParam no_params[] = {
|
|
||||||
GNUNET_PQ_query_param_end
|
|
||||||
};
|
|
||||||
enum GNUNET_DB_QueryStatus qs;
|
|
||||||
|
|
||||||
if (0 > (qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
|
|
||||||
"lock_withdraw",
|
|
||||||
no_params)))
|
|
||||||
return qs;
|
|
||||||
#endif
|
|
||||||
collectable->h_coin_envelope = *h_blind;
|
|
||||||
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||||
"get_withdraw_info",
|
"get_withdraw_info",
|
||||||
params,
|
params,
|
||||||
@ -4360,8 +4345,8 @@ postgres_get_withdraw_info (
|
|||||||
* and possibly persisting the withdrawal details.
|
* and possibly persisting the withdrawal details.
|
||||||
*
|
*
|
||||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||||
* @param collectable corresponding collectable coin (blind signature)
|
* @param wih hash that uniquely identifies the withdraw operation
|
||||||
* if a coin is found
|
* @param[in,out] collectable corresponding collectable coin (blind signature) if a coin is found; possibly updated if a (different) signature exists already
|
||||||
* @param now current time (rounded)
|
* @param now current time (rounded)
|
||||||
* @param[out] found set to true if the reserve was found
|
* @param[out] found set to true if the reserve was found
|
||||||
* @param[out] balance_ok set to true if the balance was sufficient
|
* @param[out] balance_ok set to true if the balance was sufficient
|
||||||
@ -4372,7 +4357,8 @@ postgres_get_withdraw_info (
|
|||||||
static enum GNUNET_DB_QueryStatus
|
static enum GNUNET_DB_QueryStatus
|
||||||
postgres_do_withdraw (
|
postgres_do_withdraw (
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
|
const struct TALER_WithdrawIdentificationHash *wih,
|
||||||
|
struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
|
||||||
struct GNUNET_TIME_Timestamp now,
|
struct GNUNET_TIME_Timestamp now,
|
||||||
bool *found,
|
bool *found,
|
||||||
bool *balance_ok,
|
bool *balance_ok,
|
||||||
@ -4382,6 +4368,7 @@ postgres_do_withdraw (
|
|||||||
struct PostgresClosure *pg = cls;
|
struct PostgresClosure *pg = cls;
|
||||||
struct GNUNET_TIME_Timestamp gc;
|
struct GNUNET_TIME_Timestamp gc;
|
||||||
struct GNUNET_PQ_QueryParam params[] = {
|
struct GNUNET_PQ_QueryParam params[] = {
|
||||||
|
GNUNET_PQ_query_param_auto_from_type (wih),
|
||||||
TALER_PQ_query_param_amount (&collectable->amount_with_fee),
|
TALER_PQ_query_param_amount (&collectable->amount_with_fee),
|
||||||
GNUNET_PQ_query_param_auto_from_type (&collectable->denom_pub_hash),
|
GNUNET_PQ_query_param_auto_from_type (&collectable->denom_pub_hash),
|
||||||
GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_pub),
|
GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_pub),
|
||||||
@ -4392,6 +4379,9 @@ postgres_do_withdraw (
|
|||||||
GNUNET_PQ_query_param_timestamp (&gc),
|
GNUNET_PQ_query_param_timestamp (&gc),
|
||||||
GNUNET_PQ_query_param_end
|
GNUNET_PQ_query_param_end
|
||||||
};
|
};
|
||||||
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
|
bool no_out_sig;
|
||||||
|
struct TALER_BlindedDenominationSignature out_sig;
|
||||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
GNUNET_PQ_result_spec_bool ("reserve_found",
|
GNUNET_PQ_result_spec_bool ("reserve_found",
|
||||||
found),
|
found),
|
||||||
@ -4403,18 +4393,33 @@ postgres_do_withdraw (
|
|||||||
&kyc->payment_target_uuid),
|
&kyc->payment_target_uuid),
|
||||||
GNUNET_PQ_result_spec_uint64 ("ruuid",
|
GNUNET_PQ_result_spec_uint64 ("ruuid",
|
||||||
ruuid),
|
ruuid),
|
||||||
|
GNUNET_PQ_result_spec_allow_null (
|
||||||
|
TALER_PQ_result_spec_blinded_denom_sig ("out_denom_sig",
|
||||||
|
&out_sig),
|
||||||
|
&no_out_sig),
|
||||||
GNUNET_PQ_result_spec_end
|
GNUNET_PQ_result_spec_end
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
memset (&out_sig,
|
||||||
|
0,
|
||||||
|
sizeof (out_sig));
|
||||||
|
#endif
|
||||||
gc = GNUNET_TIME_absolute_to_timestamp (
|
gc = GNUNET_TIME_absolute_to_timestamp (
|
||||||
GNUNET_TIME_absolute_add (now.abs_time,
|
GNUNET_TIME_absolute_add (now.abs_time,
|
||||||
pg->legal_reserve_expiration_time));
|
pg->legal_reserve_expiration_time));
|
||||||
kyc->type = TALER_EXCHANGEDB_KYC_WITHDRAW;
|
kyc->type = TALER_EXCHANGEDB_KYC_WITHDRAW;
|
||||||
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||||
"call_withdraw",
|
"call_withdraw",
|
||||||
params,
|
params,
|
||||||
rs);
|
rs);
|
||||||
|
if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) &&
|
||||||
|
(! no_out_sig) )
|
||||||
|
{
|
||||||
|
TALER_blinded_denom_sig_free (&collectable->sig);
|
||||||
|
collectable->sig = out_sig;
|
||||||
|
}
|
||||||
|
return qs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -9373,20 +9378,21 @@ postgres_select_reserve_closed_above_serial_id (
|
|||||||
* from given the hash of the blinded coin.
|
* from given the hash of the blinded coin.
|
||||||
*
|
*
|
||||||
* @param cls closure
|
* @param cls closure
|
||||||
* @param h_blind_ev hash of the blinded coin
|
* @param wih hash that uniquely identifies the withdraw request
|
||||||
* @param[out] reserve_pub set to information about the reserve (on success only)
|
* @param[out] reserve_pub set to information about the reserve (on success only)
|
||||||
* @param[out] reserve_out_serial_id set to row of the @a h_blind_ev in reserves_out
|
* @param[out] reserve_out_serial_id set to row of the @a h_blind_ev in reserves_out
|
||||||
* @return transaction status code
|
* @return transaction status code
|
||||||
*/
|
*/
|
||||||
static enum GNUNET_DB_QueryStatus
|
static enum GNUNET_DB_QueryStatus
|
||||||
postgres_get_reserve_by_h_blind (void *cls,
|
postgres_get_reserve_by_wih (
|
||||||
const struct TALER_BlindedCoinHash *h_blind_ev,
|
void *cls,
|
||||||
struct TALER_ReservePublicKeyP *reserve_pub,
|
const struct TALER_WithdrawIdentificationHash *wih,
|
||||||
uint64_t *reserve_out_serial_id)
|
struct TALER_ReservePublicKeyP *reserve_pub,
|
||||||
|
uint64_t *reserve_out_serial_id)
|
||||||
{
|
{
|
||||||
struct PostgresClosure *pg = cls;
|
struct PostgresClosure *pg = cls;
|
||||||
struct GNUNET_PQ_QueryParam params[] = {
|
struct GNUNET_PQ_QueryParam params[] = {
|
||||||
GNUNET_PQ_query_param_auto_from_type (h_blind_ev),
|
GNUNET_PQ_query_param_auto_from_type (wih),
|
||||||
GNUNET_PQ_query_param_end
|
GNUNET_PQ_query_param_end
|
||||||
};
|
};
|
||||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
@ -9398,7 +9404,7 @@ postgres_get_reserve_by_h_blind (void *cls,
|
|||||||
};
|
};
|
||||||
|
|
||||||
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||||
"reserve_by_h_blind",
|
"reserve_by_wih",
|
||||||
params,
|
params,
|
||||||
rs);
|
rs);
|
||||||
}
|
}
|
||||||
@ -11663,8 +11669,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
|
|||||||
= &postgres_select_recoup_refresh_above_serial_id;
|
= &postgres_select_recoup_refresh_above_serial_id;
|
||||||
plugin->select_reserve_closed_above_serial_id
|
plugin->select_reserve_closed_above_serial_id
|
||||||
= &postgres_select_reserve_closed_above_serial_id;
|
= &postgres_select_reserve_closed_above_serial_id;
|
||||||
plugin->get_reserve_by_h_blind
|
plugin->get_reserve_by_wih
|
||||||
= &postgres_get_reserve_by_h_blind;
|
= &postgres_get_reserve_by_wih;
|
||||||
plugin->get_old_coin_by_h_blind
|
plugin->get_old_coin_by_h_blind
|
||||||
= &postgres_get_old_coin_by_h_blind;
|
= &postgres_get_old_coin_by_h_blind;
|
||||||
plugin->insert_denomination_revocation
|
plugin->insert_denomination_revocation
|
||||||
|
@ -1346,6 +1346,7 @@ run (void *cls)
|
|||||||
struct GNUNET_TIME_Timestamp now;
|
struct GNUNET_TIME_Timestamp now;
|
||||||
struct TALER_WireSaltP salt;
|
struct TALER_WireSaltP salt;
|
||||||
struct TALER_CoinPubHash c_hash;
|
struct TALER_CoinPubHash c_hash;
|
||||||
|
struct TALER_WithdrawIdentificationHash wih;
|
||||||
uint64_t known_coin_id;
|
uint64_t known_coin_id;
|
||||||
uint64_t rrc_serial;
|
uint64_t rrc_serial;
|
||||||
struct TALER_EXCHANGEDB_Refresh refresh;
|
struct TALER_EXCHANGEDB_Refresh refresh;
|
||||||
@ -1383,7 +1384,7 @@ run (void *cls)
|
|||||||
plugin->create_tables (plugin->cls))
|
plugin->create_tables (plugin->cls))
|
||||||
{
|
{
|
||||||
result = 77;
|
result = 77;
|
||||||
goto drop;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
plugin->preflight (plugin->cls);
|
plugin->preflight (plugin->cls);
|
||||||
FAILIF (GNUNET_OK !=
|
FAILIF (GNUNET_OK !=
|
||||||
@ -1499,9 +1500,14 @@ run (void *cls)
|
|||||||
&cbc.denom_pub_hash,
|
&cbc.denom_pub_hash,
|
||||||
&cbc.h_coin_envelope));
|
&cbc.h_coin_envelope));
|
||||||
GNUNET_assert (GNUNET_OK ==
|
GNUNET_assert (GNUNET_OK ==
|
||||||
TALER_denom_sign_blinded (&cbc.sig,
|
TALER_withdraw_request_hash (&pd.blinded_planchet,
|
||||||
&dkp->priv,
|
&cbc.denom_pub_hash,
|
||||||
&pd.blinded_planchet));
|
&wih)); GNUNET_assert (
|
||||||
|
GNUNET_OK ==
|
||||||
|
TALER_denom_sign_blinded (
|
||||||
|
&cbc.sig,
|
||||||
|
&dkp->priv,
|
||||||
|
&pd.blinded_planchet));
|
||||||
TALER_blinded_planchet_free (&pd.blinded_planchet);
|
TALER_blinded_planchet_free (&pd.blinded_planchet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1511,6 +1517,7 @@ run (void *cls)
|
|||||||
GNUNET_assert (GNUNET_OK ==
|
GNUNET_assert (GNUNET_OK ==
|
||||||
TALER_amount_set_zero (CURRENCY,
|
TALER_amount_set_zero (CURRENCY,
|
||||||
&cbc.withdraw_fee));
|
&cbc.withdraw_fee));
|
||||||
|
|
||||||
{
|
{
|
||||||
bool found;
|
bool found;
|
||||||
bool balance_ok;
|
bool balance_ok;
|
||||||
@ -1519,6 +1526,7 @@ run (void *cls)
|
|||||||
|
|
||||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
||||||
plugin->do_withdraw (plugin->cls,
|
plugin->do_withdraw (plugin->cls,
|
||||||
|
&wih,
|
||||||
&cbc,
|
&cbc,
|
||||||
now,
|
now,
|
||||||
&found,
|
&found,
|
||||||
@ -1540,16 +1548,16 @@ run (void *cls)
|
|||||||
value.fraction,
|
value.fraction,
|
||||||
value.currency));
|
value.currency));
|
||||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
||||||
plugin->get_reserve_by_h_blind (plugin->cls,
|
plugin->get_reserve_by_wih (plugin->cls,
|
||||||
&cbc.h_coin_envelope,
|
&wih,
|
||||||
&reserve_pub3,
|
&reserve_pub3,
|
||||||
&reserve_out_serial_id));
|
&reserve_out_serial_id));
|
||||||
FAILIF (0 != GNUNET_memcmp (&reserve_pub,
|
FAILIF (0 != GNUNET_memcmp (&reserve_pub,
|
||||||
&reserve_pub3));
|
&reserve_pub3));
|
||||||
|
|
||||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
||||||
plugin->get_withdraw_info (plugin->cls,
|
plugin->get_withdraw_info (plugin->cls,
|
||||||
&cbc.h_coin_envelope,
|
&wih,
|
||||||
&cbc2));
|
&cbc2));
|
||||||
FAILIF (0 != GNUNET_memcmp (&cbc2.reserve_sig,
|
FAILIF (0 != GNUNET_memcmp (&cbc2.reserve_sig,
|
||||||
&cbc.reserve_sig));
|
&cbc.reserve_sig));
|
||||||
@ -2400,6 +2408,7 @@ drop:
|
|||||||
rh = NULL;
|
rh = NULL;
|
||||||
GNUNET_break (GNUNET_OK ==
|
GNUNET_break (GNUNET_OK ==
|
||||||
plugin->drop_tables (plugin->cls));
|
plugin->drop_tables (plugin->cls));
|
||||||
|
cleanup:
|
||||||
if (NULL != dkp)
|
if (NULL != dkp)
|
||||||
destroy_denom_key_pair (dkp);
|
destroy_denom_key_pair (dkp);
|
||||||
if (NULL != revealed_coins)
|
if (NULL != revealed_coins)
|
||||||
|
@ -571,6 +571,22 @@ struct TALER_BlindedCoinHash
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash used to uniquely represent a withdraw process so as to perform
|
||||||
|
* idempotency checks (and prevent clients from harmfully replaying withdraw
|
||||||
|
* operations with problematic variations on the inputs). In the CS case,
|
||||||
|
* this is a hash over the DK and nonce, while in the RSA case, it is simply a
|
||||||
|
* hash over the DK and the blinded coin.
|
||||||
|
*/
|
||||||
|
struct TALER_WithdrawIdentificationHash
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Actual hash value.
|
||||||
|
*/
|
||||||
|
struct GNUNET_HashCode hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash used to represent the hash of the public
|
* Hash used to represent the hash of the public
|
||||||
* key of a coin (without blinding).
|
* key of a coin (without blinding).
|
||||||
@ -1308,6 +1324,22 @@ TALER_coin_ev_hash (const struct TALER_BlindedPlanchet *blinded_planchet,
|
|||||||
struct TALER_BlindedCoinHash *bch);
|
struct TALER_BlindedCoinHash *bch);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the hash to uniquely identify a withdraw
|
||||||
|
* request.
|
||||||
|
*
|
||||||
|
* @param blinded_planchet blinded planchet
|
||||||
|
* @param denom_hash hash of the denomination publick key
|
||||||
|
* @param[out] wih where to write the hash
|
||||||
|
* @return #GNUNET_OK when successful, #GNUNET_SYSERR if an internal error occured
|
||||||
|
*/
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_withdraw_request_hash (
|
||||||
|
const struct TALER_BlindedPlanchet *blinded_planchet,
|
||||||
|
const struct TALER_DenominationHash *denom_hash,
|
||||||
|
struct TALER_WithdrawIdentificationHash *wih);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the hash of a coin.
|
* Compute the hash of a coin.
|
||||||
*
|
*
|
||||||
|
@ -2476,20 +2476,19 @@ struct TALER_EXCHANGEDB_Plugin
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locate the response for a withdraw request under the
|
* Locate the response for a withdraw request under a hash that uniquely
|
||||||
* key of the hash of the blinded message. Used to ensure
|
* identifies the withdraw operation. Used to ensure idempotency of the
|
||||||
* idempotency of the request.
|
* request.
|
||||||
*
|
*
|
||||||
* @param cls the @e cls of this struct with the plugin-specific state
|
* @param cls the @e cls of this struct with the plugin-specific state
|
||||||
* @param h_blind hash of the blinded coin to be signed (will match
|
* @param wih hash that uniquely identifies the withdraw operation
|
||||||
* `h_coin_envelope` in the @a collectable to be returned)
|
* @param[out] collectable corresponding collectable coin (blind signature)
|
||||||
* @param collectable corresponding collectable coin (blind signature)
|
|
||||||
* if a coin is found
|
* if a coin is found
|
||||||
* @return statement execution status
|
* @return statement execution status
|
||||||
*/
|
*/
|
||||||
enum GNUNET_DB_QueryStatus
|
enum GNUNET_DB_QueryStatus
|
||||||
(*get_withdraw_info)(void *cls,
|
(*get_withdraw_info)(void *cls,
|
||||||
const struct TALER_BlindedCoinHash *h_blind,
|
const struct TALER_WithdrawIdentificationHash *wih,
|
||||||
struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable);
|
struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable);
|
||||||
|
|
||||||
|
|
||||||
@ -2498,7 +2497,8 @@ struct TALER_EXCHANGEDB_Plugin
|
|||||||
* and possibly persisting the withdrawal details.
|
* and possibly persisting the withdrawal details.
|
||||||
*
|
*
|
||||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||||
* @param collectable corresponding collectable coin (blind signature)
|
* @param wih hash that uniquely identifies the withdraw operation
|
||||||
|
* @param[in,out] collectable corresponding collectable coin (blind signature)
|
||||||
* if a coin is found
|
* if a coin is found
|
||||||
* @param now current time (rounded)
|
* @param now current time (rounded)
|
||||||
* @param[out] found set to true if the reserve was found
|
* @param[out] found set to true if the reserve was found
|
||||||
@ -2510,7 +2510,8 @@ struct TALER_EXCHANGEDB_Plugin
|
|||||||
enum GNUNET_DB_QueryStatus
|
enum GNUNET_DB_QueryStatus
|
||||||
(*do_withdraw)(
|
(*do_withdraw)(
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
|
const struct TALER_WithdrawIdentificationHash *wih,
|
||||||
|
struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
|
||||||
struct GNUNET_TIME_Timestamp now,
|
struct GNUNET_TIME_Timestamp now,
|
||||||
bool *found,
|
bool *found,
|
||||||
bool *balance_ok,
|
bool *balance_ok,
|
||||||
@ -3517,16 +3518,16 @@ struct TALER_EXCHANGEDB_Plugin
|
|||||||
* from given the hash of the blinded coin.
|
* from given the hash of the blinded coin.
|
||||||
*
|
*
|
||||||
* @param cls closure
|
* @param cls closure
|
||||||
* @param h_blind_ev hash of the blinded coin
|
* @param wih hash identifying the withdraw operation
|
||||||
* @param[out] reserve_pub set to information about the reserve (on success only)
|
* @param[out] reserve_pub set to information about the reserve (on success only)
|
||||||
* @param[out] reserve_out_serial_id set to row of the @a h_blind_ev in reserves_out
|
* @param[out] reserve_out_serial_id set to row of the @a h_blind_ev in reserves_out
|
||||||
* @return transaction status code
|
* @return transaction status code
|
||||||
*/
|
*/
|
||||||
enum GNUNET_DB_QueryStatus
|
enum GNUNET_DB_QueryStatus
|
||||||
(*get_reserve_by_h_blind)(void *cls,
|
(*get_reserve_by_wih)(void *cls,
|
||||||
const struct TALER_BlindedCoinHash *h_blind_ev,
|
const struct TALER_WithdrawIdentificationHash *wih,
|
||||||
struct TALER_ReservePublicKeyP *reserve_pub,
|
struct TALER_ReservePublicKeyP *reserve_pub,
|
||||||
uint64_t *reserve_out_serial_id);
|
uint64_t *reserve_out_serial_id);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -828,4 +828,41 @@ TALER_coin_ev_hash (const struct TALER_BlindedPlanchet *blinded_planchet,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum GNUNET_GenericReturnValue
|
||||||
|
TALER_withdraw_request_hash (
|
||||||
|
const struct TALER_BlindedPlanchet *blinded_planchet,
|
||||||
|
const struct TALER_DenominationHash *denom_hash,
|
||||||
|
struct TALER_WithdrawIdentificationHash *wih)
|
||||||
|
{
|
||||||
|
struct GNUNET_HashContext *hash_context;
|
||||||
|
|
||||||
|
hash_context = GNUNET_CRYPTO_hash_context_start ();
|
||||||
|
GNUNET_CRYPTO_hash_context_read (hash_context,
|
||||||
|
denom_hash,
|
||||||
|
sizeof(*denom_hash));
|
||||||
|
switch (blinded_planchet->cipher)
|
||||||
|
{
|
||||||
|
case TALER_DENOMINATION_RSA:
|
||||||
|
GNUNET_CRYPTO_hash_context_read (
|
||||||
|
hash_context,
|
||||||
|
blinded_planchet->details.rsa_blinded_planchet.blinded_msg,
|
||||||
|
blinded_planchet->details.rsa_blinded_planchet.blinded_msg_size);
|
||||||
|
break;
|
||||||
|
case TALER_DENOMINATION_CS:
|
||||||
|
GNUNET_CRYPTO_hash_context_read (
|
||||||
|
hash_context,
|
||||||
|
&blinded_planchet->details.cs_blinded_planchet.nonce,
|
||||||
|
sizeof (struct TALER_CsNonce));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GNUNET_break (0);
|
||||||
|
GNUNET_CRYPTO_hash_context_abort (hash_context);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
GNUNET_CRYPTO_hash_context_finish (hash_context,
|
||||||
|
&wih->hash);
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* end of denom.c */
|
/* end of denom.c */
|
||||||
|
Loading…
Reference in New Issue
Block a user