aboutsummaryrefslogtreecommitdiff
path: root/src/mint/mint_db.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mint/mint_db.c')
-rw-r--r--src/mint/mint_db.c211
1 files changed, 210 insertions, 1 deletions
diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c
index 786d04ac7..91d6705c3 100644
--- a/src/mint/mint_db.c
+++ b/src/mint/mint_db.c
@@ -13,11 +13,13 @@
13 You should have received a copy of the GNU General Public License along with 13 You should have received a copy of the GNU General Public License along with
14 TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> 14 TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/ 15*/
16
16/** 17/**
17 * @file mint_db.c 18 * @file mint_db.c
18 * @brief Low-level (statement-level) database access for the mint 19 * @brief Low-level (statement-level) database access for the mint
19 * @author Florian Dold 20 * @author Florian Dold
20 * @author Christian Grothoff 21 * @author Christian Grothoff
22 * @author Sree Harsha Totakura
21 * 23 *
22 * TODO: 24 * TODO:
23 * - The mint_db.h-API should ideally be what we need to port 25 * - The mint_db.h-API should ideally be what we need to port
@@ -32,6 +34,7 @@
32#include "mint_db.h" 34#include "mint_db.h"
33#include <pthread.h> 35#include <pthread.h>
34 36
37
35/** 38/**
36 * Thread-local database connection. 39 * Thread-local database connection.
37 * Contains a pointer to PGconn or NULL. 40 * Contains a pointer to PGconn or NULL.
@@ -45,7 +48,6 @@ static pthread_key_t db_conn_threadlocal;
45 */ 48 */
46static char *TALER_MINT_db_connection_cfg_str; 49static char *TALER_MINT_db_connection_cfg_str;
47 50
48
49#define break_db_err(result) do { \ 51#define break_db_err(result) do { \
50 GNUNET_break(0); \ 52 GNUNET_break(0); \
51 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \ 53 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \
@@ -60,6 +62,213 @@ static char *TALER_MINT_db_connection_cfg_str;
60 } while (0) 62 } while (0)
61 63
62 64
65#define SQLEXEC_(conn, sql, result) \
66 do { \
67 result = PQexec (conn, sql); \
68 if (PGRES_COMMAND_OK != PQresultStatus (result)) \
69 { \
70 break_db_err (result); \
71 PQclear (result); result = NULL; \
72 goto SQLEXEC_fail; \
73 } \
74 PQclear (result); result = NULL; \
75 } while (0)
76
77
78/**
79 * Set the given connection to use a temporary schema
80 *
81 * @param db the database connection
82 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon error
83 */
84static int
85set_temporary_schema (PGconn *db)
86{
87 PGresult *result;
88
89 SQLEXEC_(db,
90 "CREATE SCHEMA IF NOT EXISTS " TALER_TEMP_SCHEMA_NAME ";"
91 "SET search_path to " TALER_TEMP_SCHEMA_NAME ";",
92 result);
93 return GNUNET_OK;
94 SQLEXEC_fail:
95 return GNUNET_SYSERR;
96}
97
98
99/**
100 * Drop the temporary taler schema. This is only useful for testcases
101 *
102 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
103 */
104int
105TALER_MINT_DB_drop_temporary (PGconn *db)
106{
107 PGresult *result;
108
109 SQLEXEC_ (db,
110 "DROP SCHEMA " TALER_TEMP_SCHEMA_NAME " CASCADE;",
111 result);
112 return GNUNET_OK;
113 SQLEXEC_fail:
114 return GNUNET_SYSERR;
115}
116
117
118/**
119 * Create the necessary tables if they are not present
120 *
121 * @param temporary should we use a temporary schema
122 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
123 */
124int
125TALER_MINT_DB_create_tables (int temporary)
126{
127 PGresult *result;
128 PGconn *conn;
129
130 result = NULL;
131 conn = PQconnectdb (TALER_MINT_db_connection_cfg_str);
132 if (CONNECTION_OK != PQstatus (conn))
133 {
134 LOG_ERROR ("Database connection failed: %s\n",
135 PQerrorMessage (conn));
136 GNUNET_break (0);
137 return GNUNET_SYSERR;
138 }
139 if ((GNUNET_YES == temporary)
140 && (GNUNET_SYSERR == set_temporary_schema (conn)))
141 {
142 PQfinish (conn);
143 return GNUNET_SYSERR;
144 }
145#define SQLEXEC(sql) SQLEXEC_(conn, sql, result);
146 /* reserves table is for summarization of a reserve. It is updated when new
147 funds are added and existing funds are withdrawn */
148 SQLEXEC ("CREATE TABLE IF NOT EXISTS reserves"
149 "("
150 " reserve_pub BYTEA PRIMARY KEY"
151 ",current_balance_value INT4 NOT NULL"
152 ",current_balance_fraction INT4 NOT NULL"
153 ",balance_currency VARCHAR(4) NOT NULL"
154 ",expiration_date INT8 NOT NULL"
155 ")");
156 /* reserves_in table collects the transactions which transfer funds into the
157 reserve. The amount and expiration date for the corresponding reserve are
158 updated when new transfer funds are added. The rows of this table
159 correspond to each incoming transaction. */
160 SQLEXEC("CREATE TABLE IF NOT EXISTS reserves_in"
161 "("
162 " reserve_pub BYTEA REFERENCES reserves (reserve_pub) ON DELETE CASCADE"
163 ",balance_value INT4 NOT NULL"
164 ",balance_fraction INT4 NOT NULL"
165 ",expiration_date INT8 NOT NULL"
166 ");");
167 result = PQexec (conn,
168 "CREATE INDEX reserves_in_index ON reserves_in (reserve_pub);");
169 if (PGRES_COMMAND_OK != PQresultStatus (result))
170 {
171 ExecStatusType status = PQresultStatus (result);
172 PQclear (result);
173 result = NULL;
174 goto SQLEXEC_fail;
175 }
176 PQclear (result);
177 SQLEXEC ("CREATE TABLE IF NOT EXISTS collectable_blindcoins"
178 "("
179 "blind_ev BYTEA PRIMARY KEY"
180 ",blind_ev_sig BYTEA NOT NULL"
181 ",denom_pub BYTEA NOT NULL"
182 ",reserve_sig BYTEA NOT NULL"
183 ",reserve_pub BYTEA REFERENCES reserves (reserve_pub) ON DELETE CASCADE"
184 ");"
185 "CREATE INDEX collectable_blindcoins_index ON"
186 " collectable_blindcoins(reserve_pub)");
187 SQLEXEC("CREATE TABLE IF NOT EXISTS known_coins "
188 "("
189 " coin_pub BYTEA NOT NULL PRIMARY KEY"
190 ",denom_pub BYTEA NOT NULL"
191 ",denom_sig BYTEA NOT NULL"
192 ",expended_value INT4 NOT NULL"
193 ",expended_fraction INT4 NOT NULL"
194 ",expended_currency VARCHAR(4) NOT NULL"
195 ",refresh_session_pub BYTEA"
196 ")");
197 SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_sessions "
198 "("
199 " session_pub BYTEA PRIMARY KEY CHECK (length(session_pub) = 32)"
200 ",session_melt_sig BYTEA"
201 ",session_commit_sig BYTEA"
202 ",noreveal_index INT2 NOT NULL"
203 // non-zero if all reveals were ok
204 // and the new coin signatures are ready
205 ",reveal_ok BOOLEAN NOT NULL DEFAULT false"
206 ") ");
207 SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_order "
208 "( "
209 " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub)"
210 ",newcoin_index INT2 NOT NULL "
211 ",denom_pub BYTEA NOT NULL "
212 ",PRIMARY KEY (session_pub, newcoin_index)"
213 ") ");
214 SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_link"
215 "("
216 " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub)"
217 ",transfer_pub BYTEA NOT NULL"
218 ",link_secret_enc BYTEA NOT NULL"
219 // index of the old coin in the customer's request
220 ",oldcoin_index INT2 NOT NULL"
221 // index for cut and choose,
222 // ranges from 0 to kappa-1
223 ",cnc_index INT2 NOT NULL"
224 ")");
225 SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_coin"
226 "("
227 " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) "
228 ",link_vector_enc BYTEA NOT NULL"
229 // index of the new coin in the customer's request
230 ",newcoin_index INT2 NOT NULL"
231 // index for cut and choose,
232 ",cnc_index INT2 NOT NULL"
233 ",coin_ev BYTEA NOT NULL"
234 ")");
235 SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_melt"
236 "("
237 " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) "
238 ",coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) "
239 ",denom_pub BYTEA NOT NULL "
240 ",oldcoin_index INT2 NOT NULL"
241 ")");
242 SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_collectable"
243 "("
244 " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) "
245 ",ev_sig BYTEA NOT NULL"
246 ",newcoin_index INT2 NOT NULL"
247 ")");
248 SQLEXEC("CREATE TABLE IF NOT EXISTS deposits "
249 "( "
250 " coin_pub BYTEA NOT NULL PRIMARY KEY CHECK (length(coin_pub)=32)"
251 ",denom_pub BYTEA NOT NULL CHECK (length(denom_pub)=32)"
252 ",transaction_id INT8 NOT NULL"
253 ",amount_currency VARCHAR(4) NOT NULL"
254 ",amount_value INT4 NOT NULL"
255 ",amount_fraction INT4 NOT NULL"
256 ",merchant_pub BYTEA NOT NULL"
257 ",h_contract BYTEA NOT NULL CHECK (length(h_contract)=64)"
258 ",h_wire BYTEA NOT NULL CHECK (length(h_wire)=64)"
259 ",coin_sig BYTEA NOT NULL CHECK (length(coin_sig)=64)"
260 ",wire TEXT NOT NULL"
261 ")");
262#undef SQLEXEC
263 PQfinish (conn);
264 return GNUNET_OK;
265
266 SQLEXEC_fail:
267 PQfinish (conn);
268 return GNUNET_SYSERR;
269}
270
271
63/** 272/**
64 * Setup prepared statements. 273 * Setup prepared statements.
65 * 274 *