-complete 'melt.sql', in theory

This commit is contained in:
Christian Grothoff 2021-12-08 20:52:23 +01:00
parent e0700ad916
commit 7fdcec4c3c
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC

View File

@ -5,20 +5,15 @@
-- Check patch versioning is in place. -- Check patch versioning is in place.
-- SELECT _v.register_patch('exchange-000x', NULL, NULL); -- SELECT _v.register_patch('exchange-000x', NULL, NULL);
CREATE OR REPLACE FUNCTION exchange_do_melt(
CREATE OR REPLACE FUNCTION exchange_check_coin_balance(
IN denom_val INT8, -- value of the denomination of the coin IN denom_val INT8, -- value of the denomination of the coin
IN denom_frac INT4, -- value of the denomination of the coin IN denom_frac INT4, -- value of the denomination of the coin
IN amount_val INT8, -- requested melt amount (with fee)
IN amount_frac INT4, -- requested melt amount (with fee)
IN in_rc BYTEA, -- refresh session hash
IN in_coin_pub BYTEA, -- coin public key IN in_coin_pub BYTEA, -- coin public key
IN coin_sig BYTEA, -- melt signature IN check_recoup BOOLEAN, -- do we need to check the recoup table?
IN in_noreveal_index INT4, -- suggested random noreveal index
IN zombie_required BOOLEAN, -- do we need a zombie coin? IN zombie_required BOOLEAN, -- do we need a zombie coin?
OUT out_noreval_index INT4, -- noreveal index to actually use
OUT balance_ok BOOLEAN, -- balance satisfied? OUT balance_ok BOOLEAN, -- balance satisfied?
OUT zombie_ok BOOLEAN, -- zombie satisfied? OUT zombie_ok BOOLEAN) -- zombie satisfied?
OUT melt_ok BOOLEAN) -- everything OK?
LANGUAGE plpgsql LANGUAGE plpgsql
AS $$ AS $$
DECLARE DECLARE
@ -37,6 +32,9 @@ DECLARE
unspent_frac INT8; -- how much of coin was refunded? unspent_frac INT8; -- how much of coin was refunded?
BEGIN BEGIN
-- Note: possible future optimization: get the coin_uuid from the previous
-- 'ensure_coin_known' and pass that here instead of the coin_pub. Might help
-- a tiny bit with performance.
SELECT known_coin_id INTO coin_uuid SELECT known_coin_id INTO coin_uuid
FROM known_coins FROM known_coins
WHERE coin_pub=in_coin_pub; WHERE coin_pub=in_coin_pub;
@ -44,49 +42,17 @@ SELECT known_coin_id INTO coin_uuid
IF NOT FOUND IF NOT FOUND
THEN THEN
-- coin unknown, should be impossible! -- coin unknown, should be impossible!
out_noreveal_index=-1;
balance_ok=FALSE; balance_ok=FALSE;
zombie_ok=FALSE; zombie_ok=FALSE;
melt_ok=FALSE;
ASSERT false, 'coin unknown'; ASSERT false, 'coin unknown';
RETURN; RETURN;
END IF; END IF;
-- We optimistically insert, and then on conflict declare
-- the query successful due to idempotency.
INSERT INTO refresh_commitments
(rc
,old_known_coin_id
,old_coin_sig
,amount_with_fee_val
,amount_with_fee_frac
,noreveal_index)
VALUES
(in_rc
,coin_uuid
,coin_sig
,amount_val
,amount_frac
,in_noreveal_index)
ON CONFLICT DO NOTHING;
IF FOUND
THEN
-- already melted, get noreveal_index
SELECT noreveal_index INTO out_noreveal_index
FROM refresh_commitments
WHERE rc=in_rc ;
balance_ok=TRUE;
zombie_ok=TRUE;
melt_ok=TRUE;
RETURN;
END IF;
-- Need to check for sufficient balance...
spent_val = 0; spent_val = 0;
spent_frac = 0; spent_frac = 0;
unspent_val = 0; unspent_val = denom_val;
unspent_frac = 0; unspent_frac = denom_frac;
SELECT SELECT
SUM(amount_with_fee_val) -- overflow here is not plausible SUM(amount_with_fee_val) -- overflow here is not plausible
@ -124,156 +90,81 @@ SELECT
unspent_val = unspent_val + tmp_val; unspent_val = unspent_val + tmp_val;
unspent_frac = unspent_frac + tmp_frac; unspent_frac = unspent_frac + tmp_frac;
SELECT -- Note: even if 'check_recoup' is true, the tables below
SUM(amount_val) -- overflow here is not plausible -- are in practice likely empty (as they only apply if
,SUM(CAST(amount_frac AS INT8)) -- compute using 64 bits -- the exchange (ever) had to revoke keys).
INTO IF check_recoup
tmp_val
,tmp_frac
FROM recoup_refresh
WHERE known_coin_id=coin_uuid;
unspent_val = unspent_val + tmp_val;
unspent_frac = unspent_frac + tmp_frac;
SELECT
SUM(amount_val) -- overflow here is not plausible
,SUM(CAST(amount_frac AS INT8)) -- compute using 64 bits
INTO
tmp_val
,tmp_frac
FROM recoup
WHERE known_coin_id=coin_uuid;
spent_val = spent_val + tmp_val;
spent_frac = spent_frac + tmp_frac;
SELECT
SUM(amount_val) -- overflow here is not plausible
,SUM(CAST(amount_frac AS INT8)) -- compute using 64 bits
INTO
tmp_val
,tmp_frac
FROM recoup_refresh
JOIN refresh_revealed_coins rrc
USING (rrc_serial)
JOIN refresh_commitments rfc
ON (rrc.melt_serial_id = rfc.melt_serial_id)
WHERE rfc.old_known_coin_id=coin_uuid;
spent_val = spent_val + tmp_val;
spent_frac = spent_frac + tmp_frac;
------------------- TBD from here
SELECT
reserve_uuid
,current_balance_val
,current_balance_frac_uuid
,expiration_date
,gc_date
INTO
reserve_uuid
,reserve_val
,reserve_frac
,reserve_gc
FROM reserves
WHERE reserve_pub=reserve_pub;
IF NOT FOUND
THEN THEN
-- reserve unknown
reserve_found=FALSE;
balance_ok=FALSE;
kyc_ok=FALSE;
RETURN;
END IF;
-- We optimistically insert, and then on conflict declare SELECT
-- the query successful due to idempotency. SUM(amount_val) -- overflow here is not plausible
INSERT INTO reserves_out ,SUM(CAST(amount_frac AS INT8)) -- compute using 64 bits
(h_blind_ev INTO
,denom_serial tmp_val
,denom_sig ,tmp_frac
,reserve_uuid FROM recoup_refresh
,reserve_sig WHERE known_coin_id=coin_uuid;
,execution_date
,amount_with_fee_val
,amount_with_fee_frac)
VALUES
(h_coin_envelope
,denom_serial
,denom_sig
,reserve_uuid
,reserve_sig
,now
,amount_val
,amount_frac)
ON CONFLICT DO NOTHING;
IF NOT FOUND unspent_val = unspent_val + tmp_val;
THEN unspent_frac = unspent_frac + tmp_frac;
-- idempotent query, all constraints must be satisfied
reserve_found=TRUE;
balance_ok=TRUE;
kyc_ok=TRUE;
RETURN;
END IF;
-- Check reserve balance is sufficient. SELECT
IF (reserve_val > amount_val) SUM(amount_val) -- overflow here is not plausible
THEN ,SUM(CAST(amount_frac AS INT8)) -- compute using 64 bits
IF (reserve_frac > amount_frac) INTO
tmp_val
,tmp_frac
FROM recoup
WHERE known_coin_id=coin_uuid;
spent_val = spent_val + tmp_val;
spent_frac = spent_frac + tmp_frac;
SELECT
SUM(amount_val) -- overflow here is not plausible
,SUM(CAST(amount_frac AS INT8)) -- compute using 64 bits
INTO
tmp_val
,tmp_frac
FROM recoup_refresh
JOIN refresh_revealed_coins rrc
USING (rrc_serial)
JOIN refresh_commitments rfc
ON (rrc.melt_serial_id = rfc.melt_serial_id)
WHERE rfc.old_known_coin_id=coin_uuid;
spent_val = spent_val + tmp_val;
spent_frac = spent_frac + tmp_frac;
IF ( (0 < tmp_val) OR (0 < tmp_frac) )
THEN THEN
reserve_val=reserve_val - amount_val; -- There was a transaction that justifies the zombie
reserve_frac=reserve_frac - amount_frac; -- status, clear the flag
ELSE zombie_required=FALSE;
reserve_val=reserve_val - amount_val - 1;
reserve_frac=reserve_frac + 100000000 - amount_frac;
END IF; END IF;
END IF;
-- Actually check if the coin balance is sufficient. Verbosely. ;-)
IF (unspent_val > spent_val)
THEN
balance_ok=TRUE;
ELSE ELSE
IF (reserve_val == amount_val) AND (reserve_frac >= amount_frac) IF (reserve_val == amount_val) AND (reserve_frac >= amount_frac)
THEN THEN
reserve_val=0; balance_ok=TRUE;
reserve_frac=reserve_frac - amount_frac;
ELSE ELSE
reserve_found=TRUE;
balance_ok=FALSE; balance_ok=FALSE;
kyc_ok=FALSE; -- we do not really know or care
RETURN;
END IF; END IF;
END IF; END IF;
-- Calculate new expiration dates. zombie_ok = NOT zombie_required;
min_reserve_gc=MAX(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
WHERE
reserve_uuid=reserve_uuid;
reserve_found=TRUE;
balance_ok=TRUE;
-- Obtain KYC status based on the last wire transfer into
-- this reserve. FIXME: likely not adequate for reserves that got P2P transfers!
SELECT kyc_ok
INTO kyc_ok
FROM reserves_in
JOIN wire_targets USING (wire_target_serial_id)
WHERE reserve_uuid=reserve_uuid
LIMIT 1; -- limit 1 should not be required (without p2p transfers)
END $$; END $$;
COMMENT ON FUNCTION exchange_do_melt(INT8, INT4, BYTEA, BYTEA, BYTEA, BYTEA, BYTEA, INT8, INT8) COMMENT ON FUNCTION exchange_check_coin_balance(INT8, INT4, BYTEA, BOOLEAN, BOOLEAN)
IS 'Checks whether the coin has sufficient balance for a melt operation (or the request is repeated and was previously approved) and if so updates the database with the result'; IS 'Checks whether the coin has sufficient balance for all the operations associated with it';
-- Complete transaction -- Complete transaction