aboutsummaryrefslogtreecommitdiff
path: root/src/exchangedb
diff options
context:
space:
mode:
Diffstat (limited to 'src/exchangedb')
-rw-r--r--src/exchangedb/0003-age_withdraw.sql3
-rw-r--r--src/exchangedb/exchange-0001.sql91
-rw-r--r--src/exchangedb/exchange_do_age_withdraw.sql60
-rw-r--r--src/exchangedb/pg_do_age_withdraw.c5
-rw-r--r--src/exchangedb/pg_get_age_withdraw.c8
-rw-r--r--src/exchangedb/test_exchangedb.c5
6 files changed, 129 insertions, 43 deletions
diff --git a/src/exchangedb/0003-age_withdraw.sql b/src/exchangedb/0003-age_withdraw.sql
index 9816e466c..c85eb60f5 100644
--- a/src/exchangedb/0003-age_withdraw.sql
+++ b/src/exchangedb/0003-age_withdraw.sql
@@ -29,8 +29,7 @@ BEGIN
'(age_withdraw_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
',h_commitment BYTEA NOT NULL CONSTRAINT h_commitment_length CHECK(LENGTH(h_commitment)=64)'
',max_age SMALLINT NOT NULL CONSTRAINT max_age_positive CHECK(max_age>=0)'
- ',amount_with_fee_val INT8 NOT NULL'
- ',amount_with_fee_frac INT4 NOT NULL'
+ ',amount_with_fee TALER_AMOUNT NOT NULL'
',reserve_pub BYTEA NOT NULL CONSTRAINT reserve_pub_length CHECK(LENGTH(reserve_pub)=32)'
',reserve_sig BYTEA NOT NULL CONSTRAINT reserve_sig_length CHECK(LENGTH(reserve_sig)=64)'
',noreveal_index SMALLINT NOT NULL CONSTRAINT noreveal_index_positive CHECK(noreveal_index>=0)'
diff --git a/src/exchangedb/exchange-0001.sql b/src/exchangedb/exchange-0001.sql
index d08aab4ea..79a0dec13 100644
--- a/src/exchangedb/exchange-0001.sql
+++ b/src/exchangedb/exchange-0001.sql
@@ -137,6 +137,97 @@ COMMENT ON FUNCTION comment_partitioned_column
IS 'Generic function to create a comment on column of a table that is partitioned.';
+--------------------------------------------------------------
+-- Taler amounts and helper functiosn
+-------------------------------------------------------------
+
+DO $$
+BEGIN
+ CREATE TYPE TALER_AMOUNT
+ AS (val INT8
+ ,frac INT4);
+
+ COMMENT ON TYPE TALER_AMOUNT
+ IS 'Type to store a TALER-amount as (val, frac) pair.';
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END
+$$;
+
+CREATE PROCEDURE amount_normalize(
+ IN amount TALER_AMOUNT
+ ,OUT normalized TALER_AMOUNT
+)
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ normalized.val = amount.val + amount.frac / 100000000;
+ normalized.frac = amount.frac % 100000000;
+END $$;
+
+COMMENT ON PROCEDURE amount_normalize
+ IS 'Returns the normalized amount by adding to the .val the value of (.frac / 100000000) and removing the modulus 100000000 from .frac.';
+
+CREATE PROCEDURE amount_add(
+ IN a TALER_AMOUNT
+ ,IN b TALER_AMOUNT
+ ,OUT sum TALER_AMOUNT
+)
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ sum = (a.val + b.val, a.frac + b.frac);
+ CALL amount_normalize(sum ,sum);
+
+ IF (sum.val > (1<<52))
+ THEN
+ RAISE EXCEPTION 'addition overflow';
+ END IF;
+END $$;
+
+COMMENT ON PROCEDURE amount_add
+ IS 'Returns the normalized sum of two amounts. It raises an exception when the resulting .val is larger than 2^52';
+
+CREATE FUNCTION amount_left_minus_right(
+ IN l TALER_AMOUNT
+ ,IN r TALER_AMOUNT
+ ,OUT diff TALER_AMOUNT
+ ,OUT ok BOOLEAN
+)
+LANGUAGE plpgsql
+AS $$
+BEGIN
+
+IF (l.val > r.val)
+THEN
+ ok = TRUE;
+ IF (l.frac >= r.frac)
+ THEN
+ diff.val = l.val - r.val;
+ diff.frac = l.frac - r.frac;
+ ELSE
+ diff.val = l.val - r.val - 1;
+ diff.frac = l.frac + 100000000 - r.frac;
+ END IF;
+ELSE
+ IF (l.val = r.val) AND (l.frac >= r.frac)
+ THEN
+ diff.val = 0;
+ diff.frac = l.frac - r.frac;
+ ok = TRUE;
+ ELSE
+ diff = (-1, -1);
+ ok = FALSE;
+ END IF;
+END IF;
+
+RETURN;
+END $$;
+
+COMMENT ON FUNCTION amount_left_minus_right
+ IS 'Subtracts the right amount from the left and returns the difference and TRUE, if the left amount is larger than the right, or an invalid amount and FALSE otherwise.';
+
+
---------------------------------------------------------------------------
-- Main DB setup loop
---------------------------------------------------------------------------
diff --git a/src/exchangedb/exchange_do_age_withdraw.sql b/src/exchangedb/exchange_do_age_withdraw.sql
index 49a1433fd..e76d4ba75 100644
--- a/src/exchangedb/exchange_do_age_withdraw.sql
+++ b/src/exchangedb/exchange_do_age_withdraw.sql
@@ -16,8 +16,7 @@
-- @author Özgür Kesim
CREATE OR REPLACE FUNCTION exchange_do_age_withdraw(
- IN amount_val INT8,
- IN amount_frac INT4,
+ IN amount_with_fee TALER_AMOUNT,
IN rpub BYTEA,
IN rsig BYTEA,
IN now INT8,
@@ -38,8 +37,9 @@ LANGUAGE plpgsql
AS $$
DECLARE
reserve_gc INT8;
- reserve_val INT8;
- reserve_frac INT4;
+ difference RECORD;
+ balance TALER_AMOUNT;
+ new_balance TALER_AMOUNT;
not_before date;
earliest_date date;
BEGIN
@@ -55,8 +55,8 @@ SELECT
,gc_date
,birthday
INTO
- reserve_val
- ,reserve_frac
+ balance.val
+ ,balance.frac
,reserve_gc
,reserve_birthday
FROM exchange.reserves
@@ -102,31 +102,23 @@ END IF;
age_ok = TRUE;
required_age=0;
-
-
-- Check reserve balance is sufficient.
-IF (reserve_val > amount_val)
-THEN
- IF (reserve_frac >= amount_frac)
- THEN
- reserve_val=reserve_val - amount_val;
- reserve_frac=reserve_frac - amount_frac;
- ELSE
- reserve_val=reserve_val - amount_val - 1;
- reserve_frac=reserve_frac + 100000000 - amount_frac;
- END IF;
-ELSE
- IF (reserve_val = amount_val) AND (reserve_frac >= amount_frac)
- THEN
- reserve_val=0;
- reserve_frac=reserve_frac - amount_frac;
- ELSE
- balance_ok=FALSE;
- RETURN;
- END IF;
+SELECT *
+INTO
+ difference
+FROM
+ amount_left_minus_right(
+ balance
+ ,amount_with_fee);
+
+balance_ok = difference.ok;
+
+IF NOT balance_ok
+THEN
+ RETURN;
END IF;
-balance_ok=TRUE;
+new_balance = difference.diff;
-- Calculate new expiration dates.
min_reserve_gc=GREATEST(min_reserve_gc,reserve_gc);
@@ -134,8 +126,8 @@ min_reserve_gc=GREATEST(min_reserve_gc,reserve_gc);
-- Update reserve balance.
UPDATE reserves SET
gc_date=min_reserve_gc
- ,current_balance_val=reserve_val
- ,current_balance_frac=reserve_frac
+ ,current_balance_val=new_balance.val
+ ,current_balance_frac=new_balance.frac
WHERE
reserves.reserve_pub=rpub;
@@ -143,8 +135,7 @@ WHERE
INSERT INTO exchange.age_withdraw
(h_commitment
,max_age
- ,amount_with_fee_val
- ,amount_with_fee_frac
+ ,amount_with_fee
,reserve_pub
,reserve_sig
,noreveal_index
@@ -154,8 +145,7 @@ INSERT INTO exchange.age_withdraw
VALUES
(h_commitment
,maximum_age_committed
- ,amount_val
- ,amount_frac
+ ,amount_with_fee
,rpub
,rsig
,noreveal_index
@@ -176,6 +166,6 @@ END IF;
END $$;
-COMMENT ON FUNCTION exchange_do_age_withdraw(INT8, INT4, BYTEA, BYTEA, INT8, INT8, BYTEA, INT2, INT2, BYTEA[], INT8[], BYTEA[])
+COMMENT ON FUNCTION exchange_do_age_withdraw(TALER_AMOUNT, BYTEA, BYTEA, INT8, INT8, BYTEA, INT2, INT2, BYTEA[], INT8[], BYTEA[])
IS 'Checks whether the reserve has sufficient balance for an age-withdraw operation (or the request is repeated and was previously approved) and that age requirements are met. If so updates the database with the result. Includes storing the blinded planchets and denomination signatures, or signaling conflict';
diff --git a/src/exchangedb/pg_do_age_withdraw.c b/src/exchangedb/pg_do_age_withdraw.c
index 4fb52d466..0c79f58c9 100644
--- a/src/exchangedb/pg_do_age_withdraw.c
+++ b/src/exchangedb/pg_do_age_withdraw.c
@@ -44,7 +44,8 @@ TEH_PG_do_age_withdraw (
struct PostgresClosure *pg = cls;
struct GNUNET_TIME_Timestamp gc;
struct GNUNET_PQ_QueryParam params[] = {
- TALER_PQ_query_param_amount (&commitment->amount_with_fee),
+ TALER_PQ_query_param_amount_tuple (pg->conn,
+ &commitment->amount_with_fee),
GNUNET_PQ_query_param_auto_from_type (&commitment->reserve_pub),
GNUNET_PQ_query_param_auto_from_type (&commitment->reserve_sig),
GNUNET_PQ_query_param_timestamp (&now),
@@ -96,7 +97,7 @@ TEH_PG_do_age_withdraw (
",reserve_birthday"
",conflict"
" FROM exchange_do_age_withdraw"
- " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);");
+ " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11);");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"call_age_withdraw",
params,
diff --git a/src/exchangedb/pg_get_age_withdraw.c b/src/exchangedb/pg_get_age_withdraw.c
index a66051c71..62ccaa834 100644
--- a/src/exchangedb/pg_get_age_withdraw.c
+++ b/src/exchangedb/pg_get_age_withdraw.c
@@ -48,8 +48,9 @@ TEH_PG_get_age_withdraw (
&aw->reserve_pub),
GNUNET_PQ_result_spec_uint16 ("max_age",
&aw->max_age),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
- &aw->amount_with_fee),
+ TALER_PQ_result_spec_amount_tuple ("amount_with_fee",
+ pg->currency,
+ &aw->amount_with_fee),
GNUNET_PQ_result_spec_uint16 ("noreveal_index",
&aw->noreveal_index),
TALER_PQ_result_spec_array_blinded_coin_hash (
@@ -83,8 +84,7 @@ TEH_PG_get_age_withdraw (
",reserve_sig"
",reserve_pub"
",max_age"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",amount_with_fee"
",noreveal_index"
",h_blind_evs"
",denom_sigs"
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index ac3735b2d..36f51120a 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -1421,6 +1421,8 @@ run (void *cls)
bool found;
bool nonce_ok;
bool balance_ok;
+ bool age_ok;
+ uint16_t maximum_age;
uint64_t ruuid;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
@@ -1428,9 +1430,12 @@ run (void *cls)
NULL,
&cbc,
now,
+ false,
&found,
&balance_ok,
&nonce_ok,
+ &age_ok,
+ &maximum_age,
&ruuid));
GNUNET_assert (found);
GNUNET_assert (nonce_ok);