diff options
author | Christian Grothoff <christian@grothoff.org> | 2022-05-08 21:04:55 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2022-05-08 21:04:55 +0200 |
commit | 60c08dccecd7e1aa578e497c57cc1fb6b29b655d (patch) | |
tree | fa15a288ce6039e3856ab07e492bcb58899b06a9 /src | |
parent | 02eb80e0b24f5ea3128cb9559429e1a364b5a214 (diff) |
expand P2P query logic
Diffstat (limited to 'src')
-rw-r--r-- | src/exchange/taler-exchange-httpd_reserves_purse.c | 22 | ||||
-rw-r--r-- | src/exchangedb/exchange-0001-part.sql | 335 | ||||
-rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 14 | ||||
-rw-r--r-- | src/include/taler_exchangedb_plugin.h | 2 |
4 files changed, 183 insertions, 190 deletions
diff --git a/src/exchange/taler-exchange-httpd_reserves_purse.c b/src/exchange/taler-exchange-httpd_reserves_purse.c index ab1051593..77321b2c5 100644 --- a/src/exchange/taler-exchange-httpd_reserves_purse.c +++ b/src/exchange/taler-exchange-httpd_reserves_purse.c @@ -297,15 +297,19 @@ purse_transaction (void *cls, bool in_conflict = true; bool insufficient_funds = true; - qs = TEH_plugin->do_reserve_purse (TEH_plugin->cls, - &rpc->purse_pub, - &rpc->merge_sig, - rpc->merge_timestamp, - &rpc->reserve_sig, - &rpc->gf->fees.purse, - rpc->reserve_pub, - &in_conflict, - &insufficient_funds); + qs = TEH_plugin->do_reserve_purse ( + TEH_plugin->cls, + &rpc->purse_pub, + &rpc->merge_sig, + rpc->merge_timestamp, + &rpc->reserve_sig, + (TALER_WAMF_MODE_CREATE_FROM_PURSE_QUOTA + == rpc->flags) + ? NULL + : &rpc->gf->fees.purse, + rpc->reserve_pub, + &in_conflict, + &insufficient_funds); if (qs < 0) { if (GNUNET_DB_STATUS_SOFT_ERROR == qs) diff --git a/src/exchangedb/exchange-0001-part.sql b/src/exchangedb/exchange-0001-part.sql index b0c5171d8..a8aebfbaa 100644 --- a/src/exchangedb/exchange-0001-part.sql +++ b/src/exchangedb/exchange-0001-part.sql @@ -1327,6 +1327,7 @@ CREATE OR REPLACE FUNCTION purse_requests_insert_trigger() LANGUAGE plpgsql AS $$ BEGIN + ASSERT NOT NEW.finished,'Internal invariant violated'; INSERT INTO purse_actions (purse_pub @@ -1348,65 +1349,10 @@ COMMENT ON TRIGGER purse_requests_on_insert IS 'Here we install an entry for the purse expiration.'; -CREATE OR REPLACE FUNCTION purse_merge_insert_trigger() - RETURNS trigger - LANGUAGE plpgsql - AS $$ -DECLARE - bal_val INT8; -DECLARE - bal_frac INT4; -DECLARE - amount_val INT8; -DECLARE - amount_frac INT4; -DECLARE - was_paid BOOLEAN; -BEGIN - SELECT balance_val - ,balance_frac - ,amount_with_fee_val - ,amount_with_fee_frac - INTO bal_val - ,bal_frac - ,amount_val - ,amount_frac - FROM purse_requests - WHERE purse_pub=NEW.purse_pub; - was_paid = (bal_val > NEW.amount_val) OR - ( (bal_val = NEW.amount_val) AND - (bal_frac >= NEW.amount_frac) ); - IF (was_paid) - THEN - UPDATE purse_actions - SET action_date=0 --- "immediately" - ,partner_serial_id=NEW.partner_serial_id - WHERE purse_pub=NEW.purse_pub; - END IF; - RETURN NEW; -END $$; -COMMENT ON FUNCTION purse_merge_insert_trigger() - IS 'Triggers merge if purse is fully paid.'; - -CREATE TRIGGER purse_merges_on_insert - AFTER INSERT - ON purse_merges - FOR EACH ROW EXECUTE FUNCTION purse_merge_insert_trigger(); -COMMENT ON TRIGGER purse_merges_on_insert - ON purse_merges - IS 'Here we install an entry that triggers the merge (if the purse is already full).'; - - CREATE OR REPLACE FUNCTION purse_requests_on_update_trigger() RETURNS trigger LANGUAGE plpgsql AS $$ -DECLARE - was_merged BOOLEAN; -DECLARE - psi INT8; -- partner's serial ID (set if merged) -DECLARE - was_paid BOOLEAN; BEGIN IF (NEW.finished) THEN @@ -1430,27 +1376,6 @@ BEGIN RETURN NEW; END IF; - -- Not finished, see if we need to update the - -- trigger time and partner. - SELECT partner_serial_id - INTO psi - FROM purse_merges - WHERE purse_pub=NEW.purse_pub; - was_merged = FOUND; - was_paid = (NEW.balance_val > NEW.amount_with_fee_val) OR - ( (NEW.balance_val = NEW.amount_with_fee_val) AND - (NEW.balance_frac >= NEW.amount_with_fee_frac) ); - IF (was_merged AND was_paid) - THEN - -- FIXME: If 0==psi, why not simply DO the merge here? - -- Adding up reserve balance + setting finished - -- is hardly doing much, and could be combined - -- with the reserve update above! - UPDATE purse_actions - SET action_date=0 --- "immediately" - ,partner_serial_id=psi - WHERE purse_pub=NEW.purse_pub; - END IF; RETURN NEW; END $$; @@ -2912,7 +2837,6 @@ END $$; - CREATE OR REPLACE FUNCTION exchange_do_purse_deposit( IN in_partner_id INT8, IN in_purse_pub BYTEA, @@ -2926,6 +2850,14 @@ CREATE OR REPLACE FUNCTION exchange_do_purse_deposit( OUT out_conflict BOOLEAN) LANGUAGE plpgsql AS $$ +DECLARE + was_merged BOOLEAN; +DECLARE + psi INT8; -- partner's serial ID (set if merged) +DECLARE + was_paid BOOLEAN; +DECLARE + my_reserve_pub BYTEA; BEGIN -- Store the deposit request. @@ -3015,9 +2947,68 @@ UPDATE purse_requests out_conflict=FALSE; out_balance_ok=TRUE; +-- See if we can finish the merge or need to update the trigger time and partner. +SELECT partner_serial_id + ,reserve_pub + INTO psi + ,my_reserve_pub + FROM purse_merges + WHERE purse_pub=in_purse_pub; + +IF NOT FOUND +THEN + RETURN; +END IF; + +SELECT + 1 + FROM purse_requests + WHERE (purse_pub=in_purse_pub) + AND ( ( ( (amount_with_fee_val <= balance_val) + AND (amount_with_fee_frac <= balance_frac) ) + OR (amount_with_fee_val < balance_val) ) ); +IF NOT FOUND +THEN + RETURN; +END IF; + +IF (0 != psi) +THEN + -- The taler-exchange-router will take care of this. + UPDATE purse_actions + SET action_date=0 --- "immediately" + ,partner_serial_id=psi + WHERE purse_pub=in_purse_pub; +ELSE + -- This is a local reserve, update balance immediately. + UPDATE reserves + SET + current_balance_frac=current_balance_frac+amount_frac + - CASE + WHEN current_balance_frac + amount_frac >= 100000000 + THEN 100000000 + ELSE 0 + END, + current_balance_val=current_balance_val+amount_val + + CASE + WHEN current_balance_frac + amount_frac >= 100000000 + THEN 1 + ELSE 0 + END + WHERE reserve_pub=my_reserve_pub; + + -- ... and mark purse as finished. + UPDATE purse_requests + SET finished=true + WHERE purse_pub=in_purse_pub; +END IF; + + END $$; + + CREATE OR REPLACE FUNCTION exchange_do_purse_merge( IN in_purse_pub BYTEA, IN in_merge_sig BYTEA, @@ -3031,7 +3022,13 @@ CREATE OR REPLACE FUNCTION exchange_do_purse_merge( LANGUAGE plpgsql AS $$ DECLARE + amount_val INT8; +DECLARE + amount_frac INT4; +DECLARE my_partner_serial_id INT8; +DECLARE + my_finished BOOLEAN; BEGIN IF in_partner_url IS NULL @@ -3058,7 +3055,12 @@ out_no_partner=FALSE; -- Check purse is 'full'. -PERFORM +SELECT amount_with_fee_val + ,amount_with_fee_frac + ,finished + INTO amount_val + ,amount_frac + ,my_finished FROM purse_requests WHERE purse_pub=in_purse_pub AND balance_val >= amount_with_fee_val @@ -3072,8 +3074,6 @@ THEN END IF; out_no_balance=FALSE; - - -- Store purse merge signature, checks for purse_pub uniqueness INSERT INTO purse_merges (partner_serial_id @@ -3111,6 +3111,8 @@ THEN END IF; out_conflict=FALSE; +ASSERT NOT my_finished, 'internal invariant failed'; + -- Store account merge signature. INSERT INTO account_merges (reserve_pub @@ -3121,13 +3123,45 @@ INSERT INTO account_merges ,in_reserve_sig ,in_purse_pub); +-- If we need a wad transfer, mark purse ready for it. +IF (0 != my_partner_serial_id) +THEN + -- The taler-exchange-router will take care of this. + UPDATE purse_actions + SET action_date=0 --- "immediately" + ,partner_serial_id=NEW.partner_serial_id + WHERE purse_pub=NEW.purse_pub; +ELSE + -- This is a local reserve, update balance immediately. + UPDATE reserves + SET + current_balance_frac=current_balance_frac+amount_frac + - CASE + WHEN current_balance_frac + amount_frac >= 100000000 + THEN 100000000 + ELSE 0 + END, + current_balance_val=current_balance_val+amount_val + + CASE + WHEN current_balance_frac + amount_frac >= 100000000 + THEN 1 + ELSE 0 + END + WHERE reserve_pub=in_reserve_pub; + + -- ... and mark purse as finished. + UPDATE purse_requests + SET finished=true + WHERE purse_pub=in_purse_pub; +END IF; + RETURN; END $$; --- COMMENT ON FUNCTION exchange_do_purse_merge() --- IS 'Checks that the partner exists, the purse has not been merged with a different reserve and that the purse is full. If so, persists the merge data. Caller MUST abort the transaction on failures so as to not persist data by accident.'; +COMMENT ON FUNCTION exchange_do_purse_merge(BYTEA, BYTEA, INT8, BYTEA, VARCHAR, BYTEA) + IS 'Checks that the partner exists, the purse has not been merged with a different reserve and that the purse is full. If so, persists the merge data and either merges the purse with the reserve or marks it as ready for the taler-exchange-router. Caller MUST abort the transaction on failures so as to not persist data by accident.'; CREATE OR REPLACE FUNCTION exchange_do_reserve_purse( @@ -3135,6 +3169,7 @@ CREATE OR REPLACE FUNCTION exchange_do_reserve_purse( IN in_merge_sig BYTEA, IN in_merge_timestamp INT8, IN in_reserve_sig BYTEA, + IN in_reserve_quota BOOLEAN, IN in_purse_fee_val INT8, IN in_purse_fee_frac INT4, IN in_reserve_pub BYTEA, @@ -3142,26 +3177,8 @@ CREATE OR REPLACE FUNCTION exchange_do_reserve_purse( OUT out_conflict BOOLEAN) LANGUAGE plpgsql AS $$ -DECLARE - my_purses_active INT8; -DECLARE - my_purses_allowed INT8; -DECLARE - my_balance_val INT8; -DECLARE - my_balance_frac INT4; -DECLARE - my_kyc_passed BOOLEAN; BEGIN --- comment out for now -IF TRUE -THEN - out_no_funds=FALSE; - out_conflict=FALSE; - RETURN; -END IF; - -- Store purse merge signature, checks for purse_pub uniqueness INSERT INTO purse_merges (partner_serial_id @@ -3201,6 +3218,48 @@ END IF; out_conflict=FALSE; +IF (in_reserve_quota) +THEN + -- Increment active purses per reserve (and check this is allowed) + UPDATE reserves + SET purses_active=purses_active+1 + ,kyc_required=TRUE + WHERE reserve_pub=in_reserve_pub + AND purses_active < purses_allowed; + IF NOT FOUND + THEN + out_no_funds=TRUE; + END IF; +ELSE + -- UPDATE reserves balance (and check if balance is enough to pay the fee) + UPDATE reserves + SET + current_balance_frac=current_balance_frac-in_purse_fee_frac + + CASE + WHEN current_balance_frac < in_purse_fee_frac + THEN 100000000 + ELSE 0 + END, + current_balance_val=current_balance_val-in_purse_fee_val + - CASE + WHEN current_balance_frac < in_purse_fee_frac + THEN 1 + ELSE 0 + END + ,kyc_required=TRUE + WHERE reserve_pub=in_reserve_pub + AND ( (current_balance_val > in_purse_fee_val) OR + ( (current_balance_frac >= in_purse_fee_frac) AND + (current_balance_val >= in_purse_fee_val) ) ); + IF NOT FOUND + THEN + out_no_funds=TRUE; + END IF; +END IF; + +out_no_funds=FALSE; + + -- Store account merge signature. INSERT INTO account_merges (reserve_pub @@ -3211,82 +3270,6 @@ INSERT INTO account_merges ,in_reserve_sig ,in_purse_pub); - - --- Charge reserve for purse creation. --- FIXME: Use different type of purse --- signature in this case, so that we --- can properly account for the purse --- fees when auditing!!! -SELECT - purses_active - ,purses_allowed - ,kyc_passed - ,current_balance_val - ,current_balance_frac -INTO - my_purses_active - ,my_purses_allowed - ,my_kyc_passed - ,my_balance_val - ,my_balance_frac -FROM reserves -WHERE reserve_pub=in_reserve_pub; - -IF NOT FOUND -THEN - out_no_funds=TRUE; - -- FIXME: be more specific in the returned - -- error that we don't know the reserve - -- (instead of merely saying it has no funds) - RETURN; -END IF; - -IF NOT my_kyc_passed -THEN - -- FIXME: might want to categorically disallow - -- purse creation without KYC (depending on - -- exchange settings => new argument?) -END IF; - -IF ( (my_purses_active >= my_purses_allowed) AND - ( (my_balance_val < in_purse_fee_val) OR - ( (my_balance_val <= in_purse_fee_val) AND - (my_balance_frac < in_purse_fee_frac) ) ) ) -THEN - out_no_funds=TRUE; - RETURN; -END IF; - -IF (my_purses_active < my_purses_allowed) -THEN - my_purses_active = my_purses_active + 1; -ELSE - -- FIXME: See above: we should probably have - -- very explicit wallet-approval in the - -- signature to charge the reserve! - my_balance_val = my_balance_val - in_purse_fee_val; - IF (my_balance_frac > in_purse_fee_frac) - THEN - my_balance_frac = my_balance_frac - in_purse_fee_frac; - ELSE - my_balance_val = my_balance_val - 1; - my_balance_frac = my_balance_frac + 100000000 - in_purse_fee_frac; - END IF; -END IF; - -UPDATE reserves SET - gc_date=min_reserve_gc - ,current_balance_val=my_balance_val - ,current_balance_frac=my_balance_frac - ,purses_active=my_purses_active - ,kyc_required=TRUE -WHERE - reserves.reserve_pub=rpub; - -out_no_funds=FALSE; - - END $$; diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index a4807d030..83a64be8a 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -3630,8 +3630,8 @@ prepare_statements (struct PostgresClosure *pg) " out_no_funds AS insufficient_funds" ",out_conflict AS conflict" " FROM exchange_do_reserve_purse" - " ($1, $2, $3, $4, $5, $6, $7);", - 7), + " ($1, $2, $3, $4, $5, $6, $7, $8);", + 8), /* Used in #postgres_select_purse_merge */ GNUNET_PQ_make_prepare ( "select_purse_merge", @@ -13853,7 +13853,7 @@ postgres_do_purse_merge ( * @param merge_sig signature affirming the merge * @param merge_timestamp time of the merge * @param reserve_sig signature of the reserve affirming the merge - * @param purse_fee amount to charge the reserve for the purse creation + * @param purse_fee amount to charge the reserve for the purse creation, NULL to use the quota * @param reserve_pub public key of the reserve to credit * @param[out] in_conflict set to true if @a purse_pub was merged into a different reserve already * @param[out] insufficient_funds set to true if @a reserve_pub has insufficient capacity to create another purse @@ -13872,12 +13872,16 @@ postgres_do_reserve_purse ( bool *insufficient_funds) { struct PostgresClosure *pg = cls; + struct TALER_Amount zero_fee; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (purse_pub), GNUNET_PQ_query_param_auto_from_type (merge_sig), GNUNET_PQ_query_param_timestamp (&merge_timestamp), GNUNET_PQ_query_param_auto_from_type (reserve_sig), - TALER_PQ_query_param_amount (purse_fee), + GNUNET_PQ_query_param_bool (NULL == purse_fee), + TALER_PQ_query_param_amount (NULL == purse_fee + ? &zero_fee + : purse_fee), GNUNET_PQ_query_param_auto_from_type (reserve_pub), GNUNET_PQ_query_param_end }; @@ -13889,6 +13893,8 @@ postgres_do_reserve_purse ( GNUNET_PQ_result_spec_end }; + TALER_amount_set_zero (pg->currency, + &zero_fee); return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "call_reserve_purse", params, diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 7fafdb26e..f95ba75a4 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -4779,7 +4779,7 @@ struct TALER_EXCHANGEDB_Plugin * @param merge_sig signature affirming the merge * @param merge_timestamp time of the merge * @param reserve_sig signature of the reserve affirming the merge - * @param purse_fee amount to charge the reserve for the purse creation + * @param purse_fee amount to charge the reserve for the purse creation, NULL to use the quota * @param reserve_pub public key of the reserve to credit * @param[out] in_conflict set to true if @a purse_pub was merged into a different reserve already * @param[out] insufficient_funds set to true if @a reserve_pub has insufficient capacity to create another purse |