anastasis-db_update_lifetime.c (6945B)
1 /* 2 This file is part of Anastasis 3 Copyright (C) 2020-2022 Anastasis SARL 4 5 Anastasis is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 Anastasis 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 Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file stasis/anastasis-db_update_lifetime.c 18 * @brief Anastasis database: update lifetime 19 * @author Christian Grothoff 20 */ 21 #include "platform.h" 22 #include "anastasis-db_pg.h" 23 #include "anastasis/anastasis-database/update_lifetime.h" 24 #include "anastasis/anastasis-database/transaction.h" 25 #include "anastasis/anastasis-database/preflight.h" 26 #include <taler/taler_pq_lib.h> 27 28 29 /** 30 * Update account lifetime to the maximum of the current 31 * value and @a eol. 32 * 33 * @param account_pub which account received a payment 34 * @param payment_identifier proof of payment, must be unique and match pending payment 35 * @param eol for how long is the account now paid (absolute) 36 * @return transaction status 37 */ 38 // FIXME: what is the significant delta to increment_lifetime? 39 // Should we combine these? 40 enum GNUNET_DB_QueryStatus 41 ANASTASIS_DB_update_lifetime ( 42 const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub, 43 const struct ANASTASIS_PaymentSecretP *payment_identifier, 44 struct GNUNET_TIME_Timestamp eol) 45 { 46 enum GNUNET_DB_QueryStatus qs; 47 48 PREPARE ("user_select4", 49 "SELECT" 50 " expiration_date " 51 "FROM anastasis_user" 52 " WHERE user_id=$1" 53 " FOR UPDATE;"); 54 PREPARE ("user_insert4", 55 "INSERT INTO anastasis_user " 56 "(user_id" 57 ",expiration_date" 58 ") VALUES " 59 "($1, $2);"); 60 PREPARE ("user_update4", 61 "UPDATE anastasis_user" 62 " SET " 63 " expiration_date=$1" 64 " WHERE user_id=$2;"); 65 PREPARE ("recdoc_payment_done2", 66 "UPDATE anastasis_recdoc_payment " 67 "SET" 68 " paid=TRUE " 69 "WHERE" 70 " payment_identifier=$1" 71 " AND" 72 " user_id=$2" 73 " AND" 74 " paid=FALSE;"); 75 for (unsigned int retries = 0; retries<MAX_RETRIES; retries++) 76 { 77 if (GNUNET_OK != 78 ANASTASIS_DB_start ( 79 "update lifetime")) 80 { 81 GNUNET_break (0); 82 return GNUNET_DB_STATUS_HARD_ERROR; 83 } 84 85 { 86 struct GNUNET_PQ_QueryParam params[] = { 87 GNUNET_PQ_query_param_auto_from_type (payment_identifier), 88 GNUNET_PQ_query_param_auto_from_type (account_pub), 89 GNUNET_PQ_query_param_end 90 }; 91 qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, 92 "recdoc_payment_done2", 93 params); 94 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 95 goto retry; 96 if (0 >= qs) 97 { 98 /* same payment made before, or unknown, or error 99 => no further action! */ 100 ANASTASIS_DB_rollback (); 101 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 102 "Payment existed, lifetime of account %s unchanged\n", 103 TALER_B2S (account_pub)); 104 return qs; 105 } 106 } 107 108 { 109 struct GNUNET_PQ_QueryParam params[] = { 110 GNUNET_PQ_query_param_auto_from_type (account_pub), 111 GNUNET_PQ_query_param_end 112 }; 113 struct GNUNET_TIME_Timestamp expiration; 114 struct GNUNET_PQ_ResultSpec rs[] = { 115 GNUNET_PQ_result_spec_timestamp ("expiration_date", 116 &expiration), 117 GNUNET_PQ_result_spec_end 118 }; 119 120 qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, 121 "user_select4", 122 params, 123 rs); 124 switch (qs) 125 { 126 case GNUNET_DB_STATUS_HARD_ERROR: 127 ANASTASIS_DB_rollback (); 128 return qs; 129 case GNUNET_DB_STATUS_SOFT_ERROR: 130 goto retry; 131 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 132 { 133 /* user does not exist, create new one */ 134 struct GNUNET_PQ_QueryParam iparams[] = { 135 GNUNET_PQ_query_param_auto_from_type (account_pub), 136 GNUNET_PQ_query_param_timestamp (&eol), 137 GNUNET_PQ_query_param_end 138 }; 139 140 GNUNET_break (! GNUNET_TIME_absolute_is_never (eol.abs_time)); 141 qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, 142 "user_insert4", 143 iparams); 144 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 145 "Created new account %s with expiration %s\n", 146 TALER_B2S (account_pub), 147 GNUNET_TIME_timestamp2s (eol)); 148 } 149 break; 150 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 151 { 152 /* user exists, update expiration_date */ 153 struct GNUNET_PQ_QueryParam iparams[] = { 154 GNUNET_PQ_query_param_timestamp (&expiration), 155 GNUNET_PQ_query_param_auto_from_type (account_pub), 156 GNUNET_PQ_query_param_end 157 }; 158 159 expiration = GNUNET_TIME_timestamp_max (expiration, 160 eol); 161 GNUNET_break (! GNUNET_TIME_absolute_is_never (expiration.abs_time)); 162 qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, 163 "user_update4", 164 iparams); 165 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 166 "Updated account %s to new expiration %s\n", 167 TALER_B2S (account_pub), 168 GNUNET_TIME_timestamp2s (expiration)); 169 } 170 break; 171 } 172 } 173 174 switch (qs) 175 { 176 case GNUNET_DB_STATUS_HARD_ERROR: 177 ANASTASIS_DB_rollback (); 178 return qs; 179 case GNUNET_DB_STATUS_SOFT_ERROR: 180 goto retry; 181 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 182 GNUNET_break (0); 183 ANASTASIS_DB_rollback (); 184 return GNUNET_DB_STATUS_HARD_ERROR; 185 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 186 break; 187 } 188 qs = ANASTASIS_DB_commit (); 189 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 190 goto retry; 191 if (qs < 0) 192 return GNUNET_DB_STATUS_HARD_ERROR; 193 return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; 194 retry: 195 ANASTASIS_DB_rollback (); 196 } 197 return GNUNET_DB_STATUS_SOFT_ERROR; 198 } 199 200 201 /* end of anastasis-db_update_lifetime.c */