sync

Backup service to store encrypted wallet databases (experimental)
Log | Files | Refs | Submodules | README | LICENSE

syncdb_update_block_TR.sql (4277B)


      1 --
      2 -- This file is part of TALER
      3 -- Copyright (C) 2026 Taler Systems SA
      4 --
      5 -- TALER is free software; you can redistribute it and/or modify it under the
      6 -- terms of the GNU General Public License as published by the Free Software
      7 -- Foundation; either version 3, or (at your option) any later version.
      8 --
      9 -- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10 -- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11 -- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12 --
     13 -- You should have received a copy of the GNU General Public License along with
     14 -- TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 --
     16 
     17 DROP FUNCTION IF EXISTS sync_do_update_block;
     18 CREATE FUNCTION sync_do_update_block (
     19   IN in_account_pub BYTEA,
     20   IN in_block_nonce BYTEA,
     21   IN in_prev_nonce BYTEA,
     22   IN in_next_nonce BYTEA,
     23   IN in_old_data_hash BYTEA,
     24   IN in_new_data_hash BYTEA,
     25   IN in_data_blob BYTEA,
     26   IN ina_object_uids BYTEA[],
     27   IN ina_object_incs INT2[],
     28   IN in_upload_sig BYTEA,
     29   IN in_refs_hash BYTEA,
     30   OUT out_account_missing BOOLEAN,
     31   OUT out_block_missing BOOLEAN,
     32   OUT out_outdated_write BOOLEAN,
     33   OUT out_negative_refcount BOOLEAN,
     34   OUT out_refs_missing BOOLEAN,
     35   OUT out_updated BOOLEAN,
     36   OUT out_no_change BOOLEAN,
     37   OUT out_refs_updated BOOLEAN)
     38 LANGUAGE plpgsql
     39 AS $$
     40 DECLARE
     41   my_prev_nonce BYTEA;
     42   my_next_nonce BYTEA;
     43   my_existing_hash BYTEA;
     44 BEGIN
     45   out_account_missing := FALSE;
     46   out_block_missing := FALSE;
     47   out_outdated_write := FALSE;
     48   out_negative_refcount := FALSE;
     49   out_refs_missing := FALSE;
     50   out_updated := FALSE;
     51   out_no_change := FALSE;
     52   out_refs_updated := FALSE;
     53 
     54   -- Check if account exists and has valid payment
     55   SELECT a.out_account_missing
     56     INTO out_account_missing
     57     FROM sync_check_account_payment(in_account_pub) AS a;
     58   IF out_account_missing
     59   THEN
     60     RETURN;
     61   END IF;
     62 
     63   -- Check if old block exists
     64   SELECT prev_nonce
     65         ,next_nonce
     66         ,block_hash
     67     INTO my_prev_nonce
     68         ,my_next_nonce
     69         ,my_existing_hash
     70     FROM blocks
     71    WHERE account_pub = in_account_pub
     72      AND nonce = in_block_nonce;
     73 
     74   IF NOT FOUND
     75   THEN
     76     out_block_missing := TRUE;
     77     RETURN;
     78   END IF;
     79 
     80   -- Is the new hash identical?
     81   IF my_existing_hash = in_new_data_hash
     82   THEN
     83     out_no_change := TRUE;
     84     RETURN;
     85   END IF;
     86 
     87   -- Does existing hash matches expected old hash?
     88   -- Does previous and next nonces match expectations?
     89   IF my_existing_hash IS DISTINCT FROM in_old_data_hash OR
     90      my_prev_nonce IS DISTINCT FROM in_prev_nonce OR
     91      my_next_nonce IS DISTINCT FROM in_next_nonce
     92   THEN
     93     out_outdated_write := TRUE;
     94     RETURN;
     95   END IF;
     96 
     97   -- Check referenced objects exist and no increment underflows,
     98   -- before we touch anything
     99   SELECT c.out_negative_refcount
    100         ,c.out_refs_missing
    101     INTO out_negative_refcount
    102         ,out_refs_missing
    103     FROM sync_check_object_refcounts_pre(in_account_pub,
    104                                          ina_object_uids,
    105                                          ina_object_incs) AS c;
    106   IF out_negative_refcount OR out_refs_missing
    107   THEN
    108     RETURN;
    109   END IF;
    110 
    111   -- Try to update existing block in place; the upload signature and
    112   -- its signed context are stored with the block
    113   UPDATE blocks
    114      SET block_hash = in_new_data_hash
    115         ,data_blob = in_data_blob
    116         ,upload_sig = in_upload_sig
    117         ,old_hash = in_old_data_hash
    118         ,refs_hash = in_refs_hash
    119   WHERE account_pub = in_account_pub
    120     AND nonce = in_block_nonce;
    121 
    122   IF NOT FOUND
    123   THEN
    124     RAISE EXCEPTION 'block % vanished for account %',
    125       in_block_nonce, in_account_pub;
    126   END IF;
    127 
    128   -- Update object refcounts and delete unreferenced objects; the
    129   -- pre-check above means this can only fail on a concurrent change
    130   SELECT u.out_negative_refcount
    131         ,u.out_refs_updated
    132     INTO out_negative_refcount
    133         ,out_refs_updated
    134     FROM sync_update_object_refcounts(in_account_pub,
    135                                       ina_object_uids,
    136                                       ina_object_incs) AS u;
    137   IF NOT out_refs_updated
    138   THEN
    139     RAISE EXCEPTION 'object refcounts changed concurrently for account %',
    140       in_account_pub;
    141   END IF;
    142 
    143   out_updated := TRUE;
    144 END $$;